suppressPackageStartupMessages({

library(ArchR)
library(tidyverse)
library(SingleCellExperiment)
library(zellkonverter)
library(dtwclust)
})
proj <- loadArchRProject("11_added_Ricards_peaks_p2g_entire_chromosome", showLogo = FALSE)
## Successfully loaded ArchRProject!
#saveArchRProject(proj, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/11_added_Ricards_peaks_p2g_entire_chromosome")

KNN cell aggregates from ArchR

To compute peak-to-gene links, cell aggregates are created to overcome sparsity as described above. To create cell aggregates, 500 cells are randomly sampled from a low-dimensional embedding, eg. PCA space and the 50 nearest neighbors of each cell are determined. This way ArchR creates 500 aggregates, each consisting of 50 cells. Below, I used these aggregates for computing correlations between different gene activity scores, however the results did not look very usable, since a lot of negative correlations were obtained this way. This might be due to theses aggregates not being representative, too small or too few. I decided to not use these aggreagates, but instaed used SEACells, which is a tool for creating cell aggregates (“metacells”).

rna_knn <- readRDS("11_added_Ricards_peaks/Peak2GeneLinks/seRNA-Group-KNN.rds")
rna_agg_mat <- assays(rna_knn)[[1]]
rownames(rna_agg_mat) <- rowData(rna_knn)$name

cell_agg_list <- metadata(rna_knn)[[1]]


knn_aggregates <- function(matrix, cell_agg_list){
  # empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = dim(matrix)[1],
                ncol = length(cell_agg_list),
                dimnames = list(rownames(matrix), NULL))
  
  for (i in seq.int(length(cell_agg_list))) {
    agg[, i] <- rowSums(matrix[, cell_agg_list[[i]]])
  }
  return(agg)
}


rna_agg <- knn_aggregates(expr_mat_sub, cell_agg_list)
agg_p2g_knn <- knn_aggregates(p2g_scores, cell_agg_list)

archr_knn <- archr_scores_mat[as.vector(rownames(agg_p2g_knn)),]
agg_archr_knn <- knn_aggregates(archr_knn, cell_agg_list)
archr_knn <- rowwise_correlations(rna_agg, agg_archr_knn, "Archr gene activity scores")
p2g_knn <- rowwise_correlations(rna_agg, agg_p2g_knn, "Peak-to-gene links activity scores")

cowplot::plot_grid(archr_knn[[2]], p2g_knn[[2]], ncol = 2)

ggplot() + geom_density_2d_filled(aes(x = p2g_knn[[1]], 
                                      y = archr_knn[[1]]), alpha = .5) +
  geom_point(aes(x = p2g_knn[[1]], y = archr_knn[[1]])) +
  geom_line(aes(x = p2g_knn[[1]], y = p2g_knn[[1]]), col = "red")
  theme(legend.position = "None") 

Functions

Function to create aggregate matrices:

# the data matrix needs to be of dimension features x cells
# the column of the colData of the sce object where celltypes are stored
# needs to be called "celltypes"
create_celltype_aggregates <- function(sce, data_matrix, celltypes) {
  #create empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = nrow(data_matrix),
                ncol = length(celltypes),
                dimnames = list(rownames(data_matrix), celltypes))
  

  for (celltype in celltypes) {
    barcodes <- rownames(colData(sce) %>%
                           as.data.frame() %>%
                           filter(celltypes == celltype))
    agg[, celltype] <- rowSums(data_matrix[, barcodes])
  }
  return(agg)
}


create_celltype_aggregates_p2g_scores <- function(gene_expr_sce, p2g_score_matrix, celltypes) {
    #create empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = nrow(p2g_score_matrix),
                ncol = length(celltypes),
                dimnames = list(rownames(p2g_score_matrix), celltypes))
  

  for (celltype in celltypes) {
    barcodes <- rownames(colData(gene_expr_sce) %>%
                           as.data.frame() %>%
                           filter(celltypes == celltype))
    agg[, celltype] <- rowSums(p2g_score_matrix[, barcodes])
  }
  return(agg)
}


create_seacell_aggregates <- function(data_matrix, seacells_df){
  agg <- matrix(data = 0,
                nrow = nrow(data_matrix),
                ncol = length(unique(seacells_df$SEACell)),
                dimnames = list(rownames(data_matrix),
                              unique(seacells_df$SEACell)))
  #stopifnot(nrow(agg) == nrow(data_matrix))
  for (seacell in unique(seacells_df$SEACell)){
    #print(seacell)
    barcodes <- (seacells_df %>% filter(SEACell == seacell))$index
    #print(barcodes)
    if (length(barcodes) == 1){
      agg[, seacell] <- data_matrix[, barcodes]
    } else{
      agg[, seacell] <- rowSums(data_matrix[, barcodes])
    }
  }
  return(agg)
}

Function to compute row-wise correlations between two matrices:

rowwise_correlations <- function(MatrixA, MatrixB, name) {
  intersect_genes <- intersect(rownames(MatrixA), rownames(MatrixB))
  MatrixA <- MatrixA[intersect_genes, ]
  MatrixB <- MatrixB[intersect_genes, ]
  correlations <- c()
  for (i in seq.int(dim(MatrixA)[1])) {
    rowA <- MatrixA[i, ]
    rowA <- rowA - mean(rowA)
    if (sd(rowA) != 0) {
      rowA <- rowA / sd(rowA)
    }
  
    rowB <- MatrixB[i, ]
    rowB <- rowB - mean(rowB)
    if (sd(rowB) != 0){
      rowB <- rowB / sd(rowB)
    }
    
    corr_value <- mean(rowA * rowB)
    correlations <- c(correlations, corr_value)
  }
  names(correlations) <- rownames(MatrixA)
  plot <- ggplot() + geom_histogram(aes(x = correlations), 
                                    bins = 200, 
                                    fill="#69b3a2") + labs(title = paste0(name))
  return(list(correlations, plot))
}

Function for ArchR KNN aggregates

# Function to compute aggregates with knn from ArchR
knn_aggregates <- function(matrix, cell_agg_list){
  # empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = dim(matrix)[1],
                ncol = length(cell_agg_list),
                dimnames = list(rownames(matrix), NULL))
  
  for (i in seq.int(length(cell_agg_list))) {
    agg[, i] <- rowSums(matrix[, cell_agg_list[[i]]])
  }
  return(agg)
}

Celltype aggregates

ArchR gene activity scores

To compute the correlations between gene expression and ArchR gene activity scores I first aggregated cells according to celltypes to compute correlations. As can be seen in the plot below, this yields very high correlation values. This is as expected, since in (Granja JM 2021) the authors compared 52 different ways of computing gene activity scores from ATAC-seq data and found their method to be the best one.

archr_scores_sub <- archr_scores_mat[as.vector(rownames(expr_mat_sub)), ]

name <- "ArchR_scores, Celltype aggregates"

archr_scores_agg <- create_celltype_aggregates(archr_scores, archr_scores_sub, 
                                               unique(colData(archr_scores)$celltypes))
stopifnot(any(is.na(archr_scores_agg)) == FALSE)

corrs <- rowwise_correlations(expr_agg, archr_scores_agg, name)
archr_corr <- corrs[1]
cowplot::plot_grid(plot_250kb + labs(title = "P2g-links activity scores, Celltype aggregates"), corrs[[2]], ncol = 2)

#, fig.width = 5, fig.height=5}
ggplot() + #geom_density2d_filled(aes(x = correlations_250kb, y = corrs[1])) #+
  geom_point(aes(x = correlations_250kb, y = corrs[[1]])) +
  geom_density_2d_filled(aes(x = correlations_250kb, y = corrs[[1]]), alpha = 0.5) +
  geom_line(aes(x =  corrs[[1]],  corrs[[1]]), color = "red") +
  labs(x = "Correlation gene expression and p2g activity scores",
       y = "Correlation gene expression and ArchR gene activity scores",
       title = "Celltype aggregates") +
  theme(legend.position = "None")

# ggplot() + geom_point(aes(x = archr_scores_sub["Hba-a1",], y = p2g_scores["Hba-a1",]))
# ggplot() + geom_point(aes(x = archr_scores_sub["Gata6",], y = p2g_scores["Hba-a1",]))

SEACell aggregates

Instead of using celltype aggregates as above, another option is to use SEACells as described in (Persad et al. 2022). These were computed using Python and the resulting cell aggregates (“metacells”) are used for aggregating gene expression and gene activity scores below. The correlations when using SEACells are much higher than the correlations obtained using the ArchR cell aggregates. For this reason I will use SEACells for computing correlations in the following steps.

seacells <- seacells %>% filter(index %in% colnames(expr_mat))

stopifnot(nrow(p2g_scores) == nrow(expr_mat_sub))

seacell_p2g_agg <- create_seacell_aggregates(p2g_scores, seacells)
seacell_rna_agg  <- create_seacell_aggregates(expr_mat_sub, seacells)
seacell_archr_agg <- create_seacell_aggregates(archr_scores_sub, seacells)


seacell_corr_p2g <- rowwise_correlations(seacell_rna_agg , seacell_p2g_agg, 
                                         "P2g links of entire chromosome, SEAcells" )

seacell_corr_archr <- rowwise_correlations(seacell_rna_agg, seacell_archr_agg, 
                                           "ArchR gene activity scores, SEAcells")

cowplot::plot_grid(seacell_corr_p2g[[2]], seacell_corr_archr[[2]], ncol = 2)

ggplot() + #geom_density2d_filled(aes(x = correlations_250kb, y = corrs[1])) #+
  geom_point(aes(x = seacell_corr_p2g[[1]], y = seacell_corr_archr[[1]])) +
  geom_density_2d_filled(aes(x = seacell_corr_p2g[[1]], y = seacell_corr_archr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]], y = seacell_corr_archr[[1]]), color = "red" )  +
  labs(x = "Correlation gene expression and p2g activity scores",
       y = "Correlation gene expression and ArchR gene activity scores",
       title = "SEACells") +
  theme(legend.position = "None")

Distance weights

Using ArchR (Granja JM 2021) I computed peak-to-gene links across the entire chromosome, but not between chromsomes. This means that a lot of correlations are found between peaks very far away from the promoter/gene they are linked to. Even though these correlations can be quite high and interactions between enhancers and promoters can occur over megabase distances, a real biological interaction becomes less likely the larger the distance is. Therefore, since wer are interested in biologically relevant and not spurious correlations. Therefore, as suggested by (Granja JM 2021), I added distance weights, such that farther away peaks linked to a gene contribute less to the gene activity score of this particular gene.

Here, I used a distance decay from the TSS, computed as follows:

\(weight = e^{-(abs(distTSS/c))}\) with \(c\) being a constant determining the exponential decay rate of the distance weights. Below I tried different rates to better understand whether we can improve the gene activity scores by giving a higher weight to close peaks than to far away peaks. As can be seen below this did not improve, the scores, but rather the scores became worse, which is probably due to the fact that most correlation values will get very small weights this way and most peaks linked with a gene, even if the correlation value is high, will not contribute to the gene activity score anymore.

**Careful: The p2g inks in ArchR are computed for peak and gene pairs which are within a certain distance from each other. However, not the real TSS of a gene is used for this, but rater the distance between start coordinate of a gene and peak start coordinate, not taking into consideration the strand directionality.

!!!!!! Check again! Because here something is wrong with the way I compute the distance weights! Sometimes I need to use the start coordinate instead of the end coordinate. Try always using the gene start coordinate instead of swapping start and end coordinates in the dataframe. Maybe this is done automaticall when converted to dataframe?

KNN aggregates

rm(meta_rna)
#rm(p2g_mat)
gc(reset = TRUE)
##              used    (Mb) gc trigger    (Mb)   max used    (Mb)
## Ncells    7263676   388.0   12756242   681.3    7263676   388.0
## Vcells 4199818138 32042.1 6153268697 46945.8 4199818138 32042.1
model_list <- c("exp(-abs(distance)/5000)", "exp(-abs(distance)/50000)",
                "exp(-abs(distance)/500000)", "exp(-abs(distance)/5000000)")

# read in knn
rna_knn <- readRDS("11_added_Ricards_peaks_p2g_entire_chromosome/Peak2GeneLinks/seRNA-Group-KNN.rds")
cell_agg_list <- metadata(rna_knn)[[1]]



# aggregate for gene expression, ArchR gene activity scores and simple p2g links
rna_agg <- knn_aggregates(expr_mat_sub, cell_agg_list)
archr_knn <- archr_scores_mat[as.vector(rownames(rna_agg)),]
agg_archr_knn <- knn_aggregates(archr_knn, cell_agg_list)
agg_p2g_knn <- knn_aggregates(p2g_scores, cell_agg_list)

# compute rowwise correlations
archr_knn <- rowwise_correlations(rna_agg, agg_archr_knn, "Archr gene activity scores, KNN aggregates")
p2g_knn <- rowwise_correlations(rna_agg, agg_p2g_knn, "Peak-to-gene links activity scores, KNN aggregates")
cowplot::plot_grid(archr_knn[[2]], p2g_knn[[2]], ncol = 2)

# prepare lists to store correlation vectors and correlation histograms
corr_list <- list(archr_knn[[1]], p2g_knn[[1]])

# compute the distance-weighted gene activity scores from p2g links using different 
# distance weight models
for (model in model_list){
  weighted_scores <- distanc_weighted_gene_activity_scores(p2g_mat_sub, 
                                                           geneModel = model, 
                                                           weight = 50000,
                                                           peak_mat = peak_mat,
                                                           links = links, 
                                                           p2g_original = p2g, 
                                                           gene_expr = gene_expr)
  agg_dist <- knn_aggregates(weighted_scores, cell_agg_list)
  dist_knn <- rowwise_correlations(rna_agg, agg_dist, name = paste0("P2g activity scores, distance weihted, model = ", model))
  stopifnot(any(is.na(dist_knn)) == FALSE)
  
  corr_list <- append(corr_list, dist_knn[[1]])
  print(dist_knn[[2]])
  #corr_plots_list <- append(corr_plots_list, dist_knn[[2]])
  
  plot <- ggplot() + #geom_density_2d_filled(aes(x = corr_list[[i]], 
                      #                y = corr_list[[1]]), alpha = .5) +
  geom_point(aes(x = dist_knn[[1]], y = corr_list[[1]])) +
  geom_line(aes(x = dist_knn[[1]], y = dist_knn[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expression & p2g activity scores",
        title = paste0(model, "KNN aggregates"),
        y = "Correlation gene expression & ArchR gene activity scores")
  print(plot)
}
## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

SEAcells

# prepare lists to store correlation vectors and correlation histograms
corr_list <- list(seacell_corr_archr[[1]], seacell_corr_p2g[[1]])

# compute the distance-weighted gene activity scores from p2g links using different 
# distance weight models
for (model in model_list){
  weighted_scores <- distanc_weighted_gene_activity_scores(p2g_mat_sub, 
                                                           geneModel = model, 
                                                           weight = 50000,
                                                           peak_mat = peak_mat,
                                                           links = links, 
                                                           p2g_original = p2g, 
                                                           gene_expr = gene_expr)
  agg_dist <- create_seacell_aggregates(weighted_scores, seacells)
  dist_knn <- rowwise_correlations(seacell_rna_agg, agg_dist, name = paste0("P2g activity scores, distance weighted, model = ", model))
  stopifnot(any(is.na(dist_knn)) == FALSE)
  
  corr_list <- append(corr_list, dist_knn[[1]])
  print(dist_knn[[2]])
  #corr_plots_list <- append(corr_plots_list, dist_knn[[2]])
  
  plot <- ggplot() + #geom_density_2d_filled(aes(x = corr_list[[i]], 
                      #                y = corr_list[[1]]), alpha = .5) +
  geom_point(aes(x = dist_knn[[1]], y = corr_list[[1]])) +
  geom_density_2d_filled(aes(x = dist_knn[[1]],
                             y = corr_list[[1]]), alpha = 0.5) +
  geom_line(aes(x = corr_list[[1]], y = corr_list[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expr. & p2g activity scores",
        title = paste0(model, "SEACells"),
        y = "Correlation gene expr. & ArchR gene activity scores")
  print(plot)
}
## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

## [1] "0 genes have only zero correlation values, so we will remove them."
## [1] "We are left with 1285 genes"
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

Gene window, no distance weights

There are two options when defining the gene window. One option is to extend +/- 100bp up- and downstream of the TSS. However, since genes have different sizes, some gene bodies might be much larger than these gene windows. The second option is to extend the gene window not from the TSS, but from the start and end corrdinate of the gene body respectively. This way, more peaks will be taken into consideration if a gene is larger, simply because the gene window will be larger. Therefore, in ArchR they use an additional weight for the gene body size to account for this effect. Here, we extend the gene window around the TSS. As can be seen in the plot below, this does not yield better results, probably, because we are removing a lot of correlations which are high and, therefore, important for the prediction.

This is not what would be expected, since some high correlations within the gene window are very likely to be biologically important and should recapitulate gene expression quite well. This is also shown by the ArchR gene activity scores, which use gene window as well to restric the influence of accessible regions to a certain window around the gene’s TSS. One reason could be that the peak-to-gene links identified by simple correlations are not biologically meaningful, therefore also very far away correlations are important for recapitulating gene expression.

Gene window around TSS

# As input for this function it is best to use only the most highly variable genes
compute_gene_window_score <- function(p2g_mat_sub, peak_mat, links, p2g_original, gene_expr){
  
  # create gene annotations with start coordinate of each gene
  # subset to contain only genes which are included in our peak2gene matrix
  gene_anno <- rowData(gene_expr) %>% 
    as.data.frame() %>%
    mutate(idxRNA = seq(nrow(.))) %>% 
    filter(name %in% rownames(p2g_mat_sub)) %>%
    mutate(strand = ifelse(strand == 1, "+", "-")) %>%
    mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
    rename(gene = name) #%>% GRanges()

  # extend gene regions +/- 100bp up- and downstream of the TSS
  gene_regions  <- resize(gene_anno %>% GRanges(), width = 1)
  extendedGeneRegion <- (suppressWarnings(extendGR(gene_regions,
                                                         upstream = 100000,
                                                         downstream = 100000)))
  # subset atac granges & get middle of each peak
  pos_atac_granges <-  metadata(p2g_original)[[1]]  %>% 
    as.data.frame() %>%
    mutate(idxATAC = seq(nrow(.))) %>% 
    # group_by(seqnames) %>%
    # mutate(idx = seq_along(seqnames)) %>% 
    # ungroup %>%
    #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
    filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
    mutate(middle = start + 300) #%>% GRanges() 
  
  #TODO: Filter for genes!
  stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
  stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
  #p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))
  
  
    # find overlapping peaks and gene window in chromosome-aware fashion
  tmp <- suppressWarnings(findOverlaps(extendedGeneRegion, pos_atac_granges %>% GRanges()))
  
  print(paste0("Out of ", subjectLength(tmp), " peaks only ",
               length(unique(subjectHits(tmp))), " peaks are found within gene window of 200kb."))
  
  
  ### some plots
  p1 <- (tmp %>% as.data.frame() %>% 
         group_by(queryHits) %>% # gene region
         summarize(n = n()) %>% # get number of peaks overlapping with a gene region
         ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
         labs(title = "number of peaks per gene region of size +/- 100kb from TSS",
             x = "number of peaks within window"))
  
  
  
  # combine the three dataframes
  p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                        by = "idxATAC")
  p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                        by = "idxRNA", suffix = c(".atac", ".rna"))

  # compute distance and distance weights 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle))# %>%
   # mutate(distance_weight = eval(parse(text=geneModel)))
  
  
  p2 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = distance), bins = 100) +
    labs(title = "Distance", x = "distance") +
    geom_vline(xintercept  = 100000, color = "red") 

  
  # p2 <- p2g_join %>% ggplot() +
  #   geom_histogram(aes(x = (distance_weight)), bins = 100) +
  #   scale_y_log10() +
  #   labs(title = "Distance Weights", x = "distance weights") 

  print(cowplot::plot_grid(p1, p2, ncol = 2))#),  ncol = 2))
  
  
  
  
    
  # create a dataframe of all peaks which overlap their corresponding gene window
  peaks_in_gene_window <- data.frame(gene = gene_regions[queryHits(tmp)]$gene, 
             peak = (pos_atac_granges %>% GRanges())[subjectHits(tmp)]$idxATAC) %>% 
    unite(peak_gene_window, gene, peak, sep = "#", remove = FALSE)
  
  # filter the p2g link dataframe for only peaks which are within a gene window
  corr_window <- p2g_join %>%
    unite(peak_gene_window, gene, idxATAC, sep = "#", remove = FALSE) %>%
    filter(peak_gene_window %in% peaks_in_gene_window$peak_gene_window) 


  ### PLOTS
  
  p1 <- corr_window %>% 
    ggplot() +
    geom_histogram(aes(x = Correlation), bins = 200, fill = "#69b3a2") +
    labs(title = "Correlation values of peaks found within gene windows")
  
  p2 <- corr_window %>% 
    ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill = "#69b3a2") +
    labs(title = "Distance between peaks and genes found within gene windows and TSS")
  
  p3 <- corr_window %>% 
    mutate(bin = cut_width(distance, width=10000, boundary=0)) %>% 
    ggplot() +
    geom_boxplot(aes(x = bin, y = Correlation), fill = "#69b3a2") +
    labs(title = "Distance and Correlation within gene window, 1000bp bins",
         x = "Distance (1000bp bins)") +
  scale_x_discrete(guide = guide_axis(angle = 90)) 

  print(cowplot::plot_grid(p1, p2, p3, ncol = 1))
  
  
  p1 <- ggplot() + 
    geom_histogram(aes(x = rowSums(p2g_mat_sub > 0)), bins = 200, fill = "#69b3a2") +
    scale_y_log10() +
    labs(title = "# peaks correlated with each gene", 
         x = "number of peaks", y = "log10(count)") 
    
  
  p2 <- ggplot() + 
    geom_histogram(aes(x = colSums(p2g_mat_sub > 0)), bins = 70, fill = "#69b3a2") +
    scale_y_log10() +
    labs(title = "# genes correlated with each peak",
         y = "log10(count)", x = "number of genes")
  
  p3 <- ggplot() + 
    geom_histogram(aes(x = rowSums(p2g_mat_sub > 0)), bins = 200, fill = "#69b3a2") +
    labs(title = "# peaks correlated with each gene", 
         x = "number of peaks", y = "count") 
    
  
  p4 <- ggplot() + 
    geom_histogram(aes(x = colSums(p2g_mat_sub > 0)), bins = 70, fill = "#69b3a2") +
    labs(title = "# genes correlated with each peak",
         y = "count", x = "number of genes")
  
  print(cowplot::plot_grid(p1, p2, p3, p4, ncol = 2))

  

  
  # 
  # 
  # peak_middle_region <- pos_atac_granges %>% GRanges()
  # # add the half width to the start of each peak
  # start(peak_middle_region) = start(peak_middle_region) + 
  #   floor(width(peak_middle_region) / 2)
  # # resize the ranges so we only have the middle of each peak
  # peak_middle_region <- resize(peak_middle_region, 1, "start")
  # 
  # # compute the distances between peak middle and gene TSS of all peaks which 
  # # overlap with a gene window
  # distance <- distance(ranges(gene_regions)[queryHits(tmp)], 
  #               ranges(resize(peak_middle_region, width = 1))[subjectHits(tmp)])
  # 
  # 
  # ### PLOT
  # # p1 <- ggplot() + geom_histogram(aes(x = distance), bins = 200) +
  # #   scale_y_log10() +
  # #   labs(title = "Distance between peak middle and gene TSS within a gene window",
  # #        y = "log10(count)") +
  # #   geom_vline(xintercept = 100000, color = "red")
  # 
  # 
  # 
  # isMinus <- BiocGenerics::which(strand(gene_regions) == "-")
  # # subtract the gene start coordinate from the tile start coordinate -> relative distances
  # signDist <- sign(start(peak_middle_region)[subjectHits(tmp)] - 
  #                    start(resize(gene_regions,1,"start"))[queryHits(tmp)])
  # # convert the direction of distance for all distances corresponding to the negative strand
  # signDist[isMinus] <- signDist[isMinus] * -1
  # 
  # 
  # distance <- distance * signDist
  # 
  # 
  # 
  # #### PLOT
  # p2 <- ggplot() + geom_histogram(aes(x = distance), bins = 500) + 
  #   scale_y_log10() +
  #   labs(title = "Relative distance of peaks to TSS within a gene window",
  #        x = "Relative distance to TSS", y = "log10(count)") + 
  #   geom_vline(xintercept = c(100000, -100000), color = "red")
  # 
  # print(p2)
  # #cowplot::plot_grid(p1, p2, ncol = 1)

  p2g_links_gene_window <- Matrix::sparseMatrix(
      i = corr_window$idxRNA, 
      j = corr_window$idxATAC, 
      x = corr_window$Correlation, 
      dims = c(nrow(expr_mat), nrow(peak_mat)),
      dimnames = list(rownames(expr_mat),rownames(peak_mat))
    )
  
  print(paste0("The peak-to-gene links matrix, restricted to a +/- 100kb window around the TSS has dimensions ", split(dim(p2g_links_gene_window), 1)))
  
  print(paste0("The maximum value is: ", max(p2g_links_gene_window), ", the minum value is: ", min(p2g_links_gene_window) ))
  
  
  
  p2g_links_gene_window <- p2g_links_gene_window[rowSums(p2g_links_gene_window) != 0, ]
  p2g_links_gene_window <- p2g_links_gene_window[, colSums(p2g_links_gene_window) != 0]
  
  print(paste0("After removing any rows and columsn which do not contain any links we are left with ", nrow(p2g_links_gene_window), " genes and ", ncol(p2g_links_gene_window), " peaks."))
  # Compute gene activity scores
  gene_window_scores <- gene_activity_scores(peak_mat_sub[colnames(p2g_links_gene_window), ], p2g_links_gene_window)
  dim(gene_window_scores)

  
  return(gene_window_scores) 
}
gene_window_scores <- compute_gene_window_score(
  p2g_mat_sub = p2g_mat_sub, 
  peak_mat = peak_mat, 
  links = links, 
  p2g_original = p2g, 
  gene_expr = gene_expr)
## [1] "Out of 133422 peaks only 22749 peaks are found within gene window of 200kb."

## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 31 rows containing missing values (geom_bar).
## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 5 rows containing missing values (geom_bar).

## [1] "The peak-to-gene links matrix, restricted to a +/- 100kb window around the TSS has dimensions c(16701, 180499)"
## [1] "The maximum value is: 0.939676699453905, the minum value is: 0"
## [1] "After removing any rows and columsn which do not contain any links we are left with 1124 genes and 5980 peaks."
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"

KNN aggregates

First, I compared the distance weigthed gene activity scores based on the ArchR KNN aggregates.

weighted_scores_agg <- knn_aggregates(gene_window_scores, cell_agg_list)
weighted_knn_corr <- rowwise_correlations(rna_agg, weighted_scores_agg,
                                          "P2g links within gene window")
weighted_knn_corr[[2]]

ggplot() +
  geom_density_2d_filled(aes(x = weighted_knn_corr[[1]], 
                             y = archr_knn[[1]][names(weighted_knn_corr[[1]])]),
                         alpha = .5) +
  geom_point(aes(x = weighted_knn_corr[[1]], y = archr_knn[[1]][names(weighted_knn_corr[[1]])])) +
  geom_line(aes(x = weighted_knn_corr[[1]], y = weighted_knn_corr[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation between gene expression and p2g activity scores",
        title = "Peak-to-gene links are restricted to a gene window of +/- 100kb around TSS",
        y = "Correlation between gene expression and ArchR gene activity scores")

SEACells

Second, I compared the distance weigths using the SEACell aggregates, which yields better results as can be seen above.

gene_window_agg <- create_seacell_aggregates(gene_window_scores, seacells)
gene_window_corr <- rowwise_correlations(seacell_rna_agg, gene_window_agg,
                                         name = "Gene window around TSS")

gene_window_corr[[2]]

ggplot() +
  geom_point(aes(x = gene_window_corr[[1]],
                 y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])])) +
  geom_density_2d_filled(aes(
    y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])],
    x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])]), 
            color = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation between gene expression and p2g activity scores, gene window",
        y = "Correlation between gene expression and ArchR gene activity scores",
       title = "Peak-to-gene links within gene window")

Effect of using different distance decay rates

How does the distance weight distribution change with different decay rates?

Here, we use the formula \(e^{\frac{-abs(distance)}{c}}\) with differen decay rates \(c \in \{5000, 50000, 500000, 5000000\}\). Additionally, we use only peaks which overlap with a +/- 100kb window from the TSS.

model_list <- c("exp(-abs(distance)/5000)", "exp(-abs(distance)/50000)",
                "exp(-abs(distance)/500000)", "exp(-abs(distance)/5000000)")


atac_granges <- metadata(p2g)[[1]]
#rna_granges <- metadata(p2g_original)[[2]]
gene_anno <- rowData(gene_expr)

# create gene annotations with start coordinate of each gene
# subset to contain only genes which are included in our peak2gene matrix
gene_anno <- gene_anno %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  filter(name %in% rownames(p2g_mat_sub)) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()

# subset atac granges & get middle of each peak
pos_atac_granges <- atac_granges  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
  mutate(middle = start + 300) #%>% GRanges() 



# combine the three dataframes
p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                      by = "idxATAC")
p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                      by = "idxRNA", suffix = c(".atac", ".rna"))

# compute distance and distance weights 
p2g_join <- p2g_join %>% 
  mutate(distance = abs(start_coord - middle)) %>%
  mutate(rel_distance = start_coord - middle)
 # mutate(distance_weight = eval(parse(text=geneModel)))

for (model in model_list){ 
# compute distance and distance weights 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle)) %>%
    mutate(distance_weight = eval(parse(text=model)))
  
  p1 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill="#69b3a2") +
    labs(title = "Distance between peaks and genes", x = "distance") +
    geom_vline(xintercept  = 5000, color = "red") +
    geom_vline(xintercept  = 250000, color = "orange")
  
  p2 <- p2g_join %>% ggplot() +
    geom_histogram(aes(x = (distance_weight)), bins = 200, fill="#69b3a2") +
    scale_y_log10() +
    labs(title = paste0("Distance_decay: ", model),
         x = "distance weights", y = "log10(counts)")
  
  print(cowplot::plot_grid(p1, p2, ncol = 2))

}
## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 2 rows containing missing values (geom_bar).

  # Relationship between distance and correlation value
# p3 <- p2g_join %>% ggplot() +
#   geom_point(aes(x = Correlation, y = distance)) +
#   labs(title = "Distance vs. correlation between peaks and genes",
#        x = "Correlation between peak and gene", 
#        y = "Distance between peak and gene")
# 
# 
# p4 <- p2g_join %>% ggplot() +
#   geom_point(aes(x = Correlation, y = distance_weight)) +
#   labs(title = "Distance vs. correlation between peaks and genes",
#        x = "Correlation between peak and gene", 
#        y = "Distance weights between peak and gene")


#cowplot::plot_grid(p1, p2, ncol = 1)

Relationship between distance and correlation values


# Olot relationship between distance and correlation as density plots
p1 <- p2g_join %>% ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

p2 <- p2g_join %>%
  filter(Correlation > 0.3) %>% 
  ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

p3 <- p2g_join %>%
  filter(Correlation > 0.6) %>% 
  ggplot() + 
  geom_density_2d_filled(aes(x = Correlation, y = distance)) +
  theme(legend.position = "None") +
  labs(title = "Relationship between distance and correlation")

cowplot::plot_grid(p1, p2, p3, ncol = 2)
p2g %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance between peaks and genes within 250kb", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance between peaks and genes within 250kb", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

p1 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000 & Correlation > 0.5) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation > 0.5") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

p2 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000 & Correlation > 0.8) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation > 0.8") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

p3 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000 & Correlation < 0.5) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance < 1e^7 bp", y = "Correlation < 0.5") + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))



p4 <- p2g_join %>%  
  mutate(bin=cut_width(distance, width=1000, boundary=0)) %>%
  filter(distance < 100000 & Correlation > 0.5) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  labs(title = "Relationship between distance and correlation of p2g links, 1kb bins",
       x = "Distance < 100kb", y = "Correlation > 0.5") + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))


cowplot::plot_grid(p1, p2, p3, p4, ncol = 2)

Lets have a look at correlation values between peaks within the promoter region of a TSS, namely 5kb upstream of the TSS.

p2g_join %>%  
  mutate(bin=cut_width(rel_distance, width=100, boundary=0)) %>%
  filter(rel_distance < 0 & rel_distance >= -5000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Distance -5kb upstream of TSS, 100bp bins",
       x = "Distance -5kb upstream of TSS", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

Try distance decay rates

rna_knn <- readRDS("11_added_Ricards_peaks_p2g_entire_chromosome/Peak2GeneLinks/seRNA-Group-KNN.rds")
#rna_agg_mat <- assays(rna_knn)[[1]]
#rownames(rna_agg_mat) <- rowData(rna_knn)$name

cell_agg_list <- metadata(rna_knn)[[1]]


knn_aggregates <- function(matrix, cell_agg_list){
  # empty matrix to store aggregates
  agg <- matrix(data = 0,
                nrow = dim(matrix)[1],
                ncol = length(cell_agg_list),
                dimnames = list(rownames(matrix), NULL))
  
  for (i in seq.int(length(cell_agg_list))) {
    agg[, i] <- rowSums(matrix[, cell_agg_list[[i]]])
  }
  return(agg)
}


rna_agg <- knn_aggregates(expr_mat_sub, cell_agg_list)
archr_knn <- archr_scores_mat[as.vector(rownames(agg_p2g_knn)),]
agg_archr_knn <- knn_aggregates(archr_knn, cell_agg_list)

agg_p2g_knn <- knn_aggregates(p2g_scores, cell_agg_list)
agg_dist <- knn_aggregates(weighted_scores, cell_agg_list)
archr_knn <- rowwise_correlations(rna_agg, agg_archr_knn, "Archr gene activity scores")
p2g_knn <- rowwise_correlations(rna_agg, agg_p2g_knn, "Peak-to-gene links activity scores")
dist_knn <- rowwise_correlations(rna_agg, agg_dist, "Peak-to_gene links activity scores weighted by distance")
cowplot::plot_grid(archr_knn[[2]], p2g_knn[[2]], dist_knn[[2]], ncol = 2)

p1 <- ggplot() + geom_density_2d_filled(aes(x = p2g_knn[[1]], 
                                      y = archr_knn[[1]]), alpha = .5) +
  geom_point(aes(x = p2g_knn[[1]], y = archr_knn[[1]])) +
  geom_line(aes(x = p2g_knn[[1]], y = p2g_knn[[1]]), col = "red") +
  theme(legend.position = "None") 
  
  
p2 <- ggplot() + geom_density_2d_filled(aes(x = dist_knn[[1]], 
                                      y = archr_knn[[1]]), alpha = .5) +
  geom_point(aes(x = dist_knn[[1]], y = archr_knn[[1]])) +
  geom_line(aes(x = dist_knn[[1]], y = dist_knn[[1]]), col = "red") +
  theme(legend.position = "None") 

cowplot::plot_grid(p1, p2, ncol = 2)

TAD boundaries

In case Hi-C data are available, TAD boundaries could aid in finding peak-to-gene links. Setting a distance decay rate to the same value for all genes and celltypes, does not give credit to the biological variability associated with gene regulation. In (Zuin J. 2022) it has been shown experimentally, that interactions between regulatory elements decay exponentially within TAD boundaries and almost disappear completely beyond TAD boundaries. Here, I restricted the peak-to-gene links identified by ArchR to within TAD boundaries and computed gene activity scores again.

tad_boundaries <- as.data.frame(read.table("jupyter_notebooks/tad_e75.bed", header = FALSE, sep = "\t", stringsAsFactors = FALSE, quote = ""))
tad_boundaries <- tad_boundaries %>% 
  rename(seqnames = V1, start = V2, end = V3) %>% 
  GRanges()

p1 <- ggplot() + geom_histogram(aes(x = width(gene_anno %>% GRanges())), 
                                    bins = 200) +
  geom_vline(xintercept = median(width(gene_anno %>% GRanges())), 
             color = "orange") +
  labs(title = paste0("Distribution of gene size, median size = ",
                      median(width(gene_anno %>% GRanges()))),
       x = "Gene size in bp")

p2 <- ggplot() + geom_histogram(aes(x = width(tad_boundaries)), bins = 200) +
  geom_vline(xintercept = median(width(tad_boundaries)), color = "orange") +
  labs(title = paste0("Distribution of TAD boundary size, median size = ",
       median(width(tad_boundaries))),
      x = "TAD boundary size in bp")

cowplot::plot_grid(p1, p2, ncol = 1)

What is the distribution of peaks and genes within TAD boundaries?

gene_anno <- rowData(gene_expr)

# create gene annotations with start coordinate of each gene
# subset to contain only genes which are included in our peak2gene matrix
gene_anno <- gene_anno %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  filter(name %in% rownames(p2g_mat_sub)) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()


# subset atac granges & get middle of each peak
pos_atac_granges <- atac_granges  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
  mutate(middle = start + 300) #%>% GRanges() 

#TODO: Filter for genes!
stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
#p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))


  # find overlapping peaks and gene window in chromosome-aware fashion
tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno %>% GRanges(), 
                                              tad_boundaries))

p1 <- tad_overlaps_genes %>% as.data.frame() %>%
  group_by(subjectHits) %>%
  summarise(n = n()) %>% 
  ggplot() + geom_histogram(aes(x = n), bins = 100) +
  labs(title = "Number of highly variable genes within a tad boundary",
       x = "number of genes/tad boundary")

tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges %>% GRanges(),
                                         tad_boundaries))


p2 <- tad_overlaps_peaks %>% as.data.frame() %>%
  group_by(subjectHits) %>%
  summarise(n = n()) %>% 
  ggplot() + geom_histogram(aes(x = n), bins = 100) +
  labs(title = "Number of peaks within a tad boundary",
       x = "number of peaks/tad boundary")


cowplot::plot_grid(p1, p2, ncol = 2)

How many p2g links are within tad boundaries?

Peak-to-gene links considered in above computations

All peak-to-gene links

```#{r, fig.width=12, fig.height=5} rm(peaks) gc(reset = TRUE)

p2g_pos <- p2g %>% as.data.frame() %>% filter(Correlation > 0) %>% unite(link, idxRNA, idxATAC, sep = “%”, remove = FALSE)

gene_anno_all <- rowData(gene_expr) %>% as.data.frame() %>% mutate(idxRNA = seq(nrow(.))) %>% filter(idxRNA %in% p2g_pos$idxRNA) %>% mutate(strand = ifelse(strand == 1, “+”, “-”)) %>% mutate(start_coord = ifelse(strand == “+”, start, end)) %>% rename(gene = name) #%>% GRanges()

subset atac granges & get middle of each peak

pos_atac_granges_all <- metadata(p2g)[[1]] %>% as.data.frame() %>% mutate(idxATAC = seq(nrow(.))) %>% # group_by(seqnames) %>% # mutate(idx = seq_along(seqnames)) %>% # ungroup %>% #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% filter(idxATAC %in% p2g_pos$idxATAC) %>% mutate(middle = start + 300) #%>% GRanges()

combine the three dataframes

p2g_join_all <- left_join(p2g_pos, as.data.frame(pos_atac_granges_all), by = “idxATAC”) p2g_join_all <- left_join(p2g_join_all, as.data.frame(gene_anno_all), by = “idxRNA”, suffix = c(“.atac”, “.rna”))

p2g_join_all <- p2g_join_all %>% mutate(distance = abs(start_coord - middle))

# find overlapping peaks and gene window in chromosome-aware fashion tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno_all %>% GRanges(), tad_boundaries))

get genes which are not found within two TAD boundaries, but only within one

within_genes <- (tad_overlaps_genes %>% as.data.frame() %>% group_by(queryHits) %>% summarise(n = n()) %>% ungroup() %>% filter(n < 2))$queryHits

print(paste0(“Out of”, nrow(gene_anno_all), " genes, “, length(unique(queryHits(tad_overlaps_genes))),” genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely “, abs(length(within_genes) - length(unique(queryHits(tad_overlaps_genes)))),”."))

We only keep genes within boundaries, but not genes crossing boundaries

tad_overlaps_genes <- tad_overlaps_genes %>% as.data.frame %>% filter(queryHits %in% within_genes) #%>% S4Vectors::as()

get peaks overlapping with tad boundaries

tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges_all %>% GRanges(), tad_boundaries))

filter for peaks overlapping tad boundaries which also contain genes

tad_overlaps_peaks <- tad_overlaps_peaks %>% as.data.frame() %>% filter(subjectHits %in% tad_overlaps_genes$subjectHits)

combine tad boundaries which contain genes and peaks

tad_combine <- left_join(tad_overlaps_genes, tad_overlaps_peaks, copy = TRUE, by = “subjectHits”, suffix = c(“.gene”, “.peak”)) %>% unite(link, queryHits.gene, queryHits.peak, sep = “%”, remove = FALSE)

genes <- gene_anno_all[tad_combine$queryHits.gene, ] %>% mutate(tad_index = tad_combine$subjectHits)

peak_coll <- pos_atac_granges_all[tad_combine$queryHits.peak, ] %>% mutate(tad_index = tad_combine$subjectHits)

gene_peak_tad_df <- left_join(genes, peak_coll, by = “tad_index”, suffic = c(“.gene”, “.peak”)) %>% unite(peak_gene_tad, gene, idxATAC, sep = “#”, remove = FALSE)

some plots

p1 <- (tad_overlaps_peaks %>% as.data.frame() %>% group_by(subjectHits) %>% # gene region summarize(n = n()) %>% # get number of peaks overlapping with a gene region ggplot() + geom_histogram(aes(x = n), bins = 100, fill=“#69b3a2”) + labs(title = “Number of peaks per tad boundary, positive p2g links”, x = “number of peaks”))

p2 <- (tad_overlaps_genes %>% as.data.frame() %>% group_by(subjectHits) %>% # gene region summarize(n = n()) %>% # get number of peaks overlapping with a gene region ggplot() + geom_histogram(aes(x = n), bins = 100, fill=“#69b3a2”) + labs(title = “Number of genes per tad boundary, positive p2g links”, x = “number of genes”))

print(cowplot::plot_grid(p1, p2, ncol = 2))

print(paste0(“The number of positive peak-to-gene links is:”, length(p2g_pos\(link))) print(paste0( "The number of positive peak-to-gene links within TAD boundaries is: ", length(tad_combine\)link)))

print(paste0(“The number of positive peak-to-gene links outside TAD boundaries is:”, length(p2g_pos\(link) - length(tad_combine\)link)))

print(paste0(“The proportion of peak-to-gene links within TAD boundaries out of all positive peak-to-gene links across the entire chromosome is”, round(length(tad_combine\(link) / length(p2g_pos\)link), 5)))

#ggplot() + geom_point(aes(x = p2g_pos\(idxATAC, y = p2g_pos\)idxRNA))

```

Distance vs. Correlation

Here I visualize the relationship between distance between peaks and genes and their respective correlation values using all positive links obtained using ArchR

p2g_join_all %>%  
  mutate(bin=cut_width(distance, width=100000, boundary=0)) %>%
  filter(distance < 10000000) %>% 
  ggplot() +
  geom_boxplot(aes(x = bin, y = Correlation), fill="#69b3a2") +
  #geom_vline(xintercept  = 250000, color = "red") +
  labs(title = "Relationship between distance and correlation of p2g links, 100kb bins",
       x = "Distance between peaks and genes within 250kb", y = "Correlation") + 
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
colPalette_celltypes = c('#532C8A',
 '#c19f70',
 '#f9decf',
 '#c9a997',
 '#B51D8D',
 '#3F84AA',
 '#9e6762',
 '#354E23',
 '#F397C0',
 '#ff891c',
 '#635547',
 '#C72228',
 '#f79083',
 '#EF4E22',
 '#989898',
 '#7F6874',
 '#8870ad',
 '#647a4f',
 '#EF5A9D',
 '#FBBE92',
 '#139992',
 '#cc7818',
 '#DFCDE4',
 '#8EC792',
 '#C594BF',
 '#C3C388',
 '#0F4A9C',
 '#FACB12',
 '#8DB5CE',
 '#1A1A1A',
 '#C9EBFB',
 '#DABE99',
 '#65A83E',
 '#005579',
 '#CDE088',
 '#f7f79e',
 '#F6BFCB')

tad_boundaries %>% as.data.frame() %>% group_by(seqnames) %>% 
  summarise(n = n()) %>% ungroup() %>%  
  ggplot() + geom_col(aes(x = seqnames, y = n, fill = seqnames), alpha = .7, ) +#, position = "dodge")
  theme(legend.position = "None") +
  scale_fill_manual(values = colPalette_celltypes) +
  labs(y = "number of tad boundaries")

TODO: Should I also remove peaks which are across TAD boundaries?

# As input for this function it is best to use only the most highly variable genes
tad_boundaries_p2g_scores <- function(p2g_mat_sub, peak_mat, links, p2g_original, gene_expr, tad_boundaries){
  atac_granges <- metadata(p2g_original)[[1]]
  #rna_granges <- metadata(p2g_original)[[2]]
  gene_anno <- rowData(gene_expr)
  
  # create gene annotations with start coordinate of each gene
  # subset to contain only genes which are included in our peak2gene matrix
  gene_anno <- gene_anno %>% as.data.frame() %>%
    mutate(idxRNA = seq(nrow(.))) %>% 
    filter(name %in% rownames(p2g_mat_sub)) %>%
    mutate(strand = ifelse(strand == 1, "+", "-")) %>%
    mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
    rename(gene = name) #%>% GRanges()


  # subset atac granges & get middle of each peak
  pos_atac_granges <- atac_granges  %>% 
    as.data.frame() %>%
    mutate(idxATAC = seq(nrow(.))) %>% 
    # group_by(seqnames) %>%
    # mutate(idx = seq_along(seqnames)) %>% 
    # ungroup %>%
    #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
    filter(idxATAC %in% colnames(p2g_mat_sub)) %>% 
    mutate(middle = start + 300) #%>% GRanges() 
  
  #TODO: Filter for genes!
  stopifnot(length(unique(links$idxATAC)) == dim(pos_atac_granges)[[1]])
  stopifnot(length(unique(links$idxRNA)) == dim(gene_anno)[[1]])
  #p2g_filt <- p2g_original %>% as.data.frame() %>% filter(gene %in% rownames(p2g_mat))
  
  
    # find overlapping peaks and gene window in chromosome-aware fashion
  tad_overlaps_genes <- suppressWarnings(findOverlaps(gene_anno %>% GRanges(), 
                                                tad_boundaries))
  
  # get genes which are not found within two TAD boundaries, but only within one
  within_genes <- (tad_overlaps_genes %>% 
  as.data.frame() %>% 
  group_by(queryHits) %>%
  summarise(n = n()) %>% ungroup() %>%
  filter(n < 2))$queryHits

  print(paste0("Out of ", nrow(gene_anno), " genes, ", length(unique(queryHits(tad_overlaps_genes))), " genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely ", length(within_genes), "."))
  
  # We only keep genes within boundaries, but not genes crossing boundaries
  tad_overlaps_genes <- tad_overlaps_genes %>% as.data.frame %>% 
    filter(queryHits %in% within_genes) #%>% S4Vectors::as()
  
  # get peaks overlapping with tad boundaries
  tad_overlaps_peaks <- suppressWarnings(findOverlaps(pos_atac_granges %>% GRanges(),
                                         tad_boundaries))
  
  # filter for peaks overlapping tad boundaries which also contain genes
  tad_overlaps_peaks <- tad_overlaps_peaks %>% as.data.frame() %>% 
    filter(subjectHits %in% tad_overlaps_genes$subjectHits)
  
  # combine tad boundaries which contain genes and peaks
  tad_combine <- left_join(tad_overlaps_genes, tad_overlaps_peaks, 
                           copy = TRUE, by = "subjectHits", suffix = c(".gene", ".peak"))
  
  
  genes <- gene_anno[tad_combine$queryHits.gene, ] %>%
    mutate(tad_index = tad_combine$subjectHits)
  
  peak_coll <- pos_atac_granges[tad_combine$queryHits.peak, ] %>% 
    mutate(tad_index = tad_combine$subjectHits)
  
  gene_peak_tad_df <- left_join(genes, peak_coll, by = "tad_index", suffic = c(".gene", ".peak")) %>%  unite(peak_gene_tad, gene, idxATAC, sep = "#", remove = FALSE)


  
  ### some plots
  p1 <- (tad_overlaps_peaks  %>% as.data.frame() %>% 
         group_by(subjectHits) %>% # gene region
         summarize(n = n()) %>% # get number of peaks overlapping with a gene region
         ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
         labs(title = "Number of peaks per tad boundary",
             x = "number of peaks"))
  
  p2 <- (tad_overlaps_genes  %>% as.data.frame() %>% 
       group_by(subjectHits) %>% # gene region
       summarize(n = n()) %>% # get number of peaks overlapping with a gene region
       ggplot() + geom_histogram(aes(x = n), bins = 100, fill="#69b3a2") +
       labs(title = "Number of hvg genes per tad boundary",
           x = "number of genes"))
  
  print(cowplot::plot_grid(p1, p2, ncol = 2))
  
  
  # combine the annotation dataframe with the p2g links dataframe
  p2g_join <- left_join(links, as.data.frame(pos_atac_granges),
                        by = "idxATAC")
  p2g_join <- left_join(p2g_join, as.data.frame(gene_anno),
                        by = "idxRNA", suffix = c(".atac", ".rna"))

  # compute distance 
  p2g_join <- p2g_join %>% 
    mutate(distance = abs(start_coord - middle))
  
  # filter for the p2g links within tad boundaries
  corr_tad_boundary <- p2g_join %>% 
    unite(peak_gene_tad, gene, idxATAC, sep = "#", remove = FALSE) %>% 
    filter(peak_gene_tad %in% gene_peak_tad_df$peak_gene_tad)

  ### PLOTS
  
  p1 <- corr_tad_boundary %>% 
    ggplot() +
    geom_histogram(aes(x = Correlation), bins = 200, fill = "#69b3a2") +
    labs(title = "Correlation values of peak-to-gene links found within tad boundaries")
  
  p2 <- corr_tad_boundary %>% 
    ggplot() +
    geom_histogram(aes(x = distance), bins = 200, fill = "#69b3a2") +
    labs(title = "Distance between peaks and TSS within tad boundary")
  
  p3 <- corr_tad_boundary %>% 
    mutate(bin = cut_width(distance, width=100000, boundary=0)) %>% 
    ggplot() +
    geom_boxplot(aes(x = bin, y = Correlation), fill = "#69b3a2") +
    labs(title = "Distance and Correlation within tad boundary, 100kb bins",
         x = "Distance (100kb bins)") +
    scale_x_discrete(guide = guide_axis(angle = 90)) 

  print(cowplot::plot_grid(p1, p2, p3, ncol = 1))
  


  
  #### PLOT
  p2 <- corr_tad_boundary %>% ggplot() +
    geom_histogram(aes(x = distance), bins = 500) + 
    scale_y_log10() +
    labs(title = "Relative distance of peaks to TSS within tad boundaries",
         x = "Relative distance to TSS", y = "log10(count)") + 
    geom_vline(xintercept = c(100000, -100000), color = "red")
  
  print(p2)
  #cowplot::plot_grid(p1, p2, ncol = 1)
  
  
  
  p2g_links_tad <- Matrix::sparseMatrix(
      i = corr_tad_boundary$idxRNA, 
      j = corr_tad_boundary$idxATAC, 
      x = corr_tad_boundary$Correlation, 
      dims = c(nrow(expr_mat), nrow(peak_mat)),
      dimnames = list(rownames(expr_mat),rownames(peak_mat))
    )
  
  
  print(paste0("The maximum value is: ", max(p2g_links_tad), ", the minum value is: ", min(p2g_links_tad) ))
  
  
  
  p2g_links_tad <- p2g_links_tad[rowSums(p2g_links_tad) != 0, ]
  p2g_links_tad <- p2g_links_tad[, colSums(p2g_links_tad) != 0]
  
  print(paste0("After removing any rows and columsn which do not contain any links we are left with ", nrow(p2g_links_tad), " genes and ", ncol(p2g_links_tad), " peaks."))
  
  
  # Compute gene activity scores
  tad_scores <- gene_activity_scores(peak_mat_sub[colnames(p2g_links_tad), ], p2g_links_tad)
  
  return(tad_scores) 
}
gc(reset = TRUE)
##              used    (Mb) gc trigger    (Mb)   max used    (Mb)
## Ncells    7542060   402.8   21423616  1144.2    7542060   402.8
## Vcells 4387697200 33475.5 7384002436 56335.5 4387697200 33475.5
tad_scores <- tad_boundaries_p2g_scores(p2g_mat_sub = p2g_mat_sub,
                                        peak_mat = peak_mat,
                                        links = links, 
                                        p2g_original = p2g, 
                                        gene_expr = gene_expr,
                                        tad_boundaries = tad_boundaries)
## [1] "Out of 1285 genes, 1090 genes are within TAD boundaries. Some of these genes even span across TAD boudnaries, namely 1038."

## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 244 rows containing missing values (geom_bar).

## [1] "The maximum value is: 0.969061504385395, the minum value is: 0"
## [1] "After removing any rows and columsn which do not contain any links we are left with 1028 genes and 17390 peaks."
## [1] "normalized the p2g matrix"
## [1] "Computed weightes sum of peaks for each gene and cell"
## [1] "Normalized for library size"
## [1] "Exponentiated matrix"
## [1] "Divided by total activity to get value between zero and one"
gc(reset = TRUE)
##              used    (Mb) gc trigger    (Mb)   max used    (Mb)
## Ncells    7944922   424.4   21423616  1144.2    7944922   424.4
## Vcells 5484933292 41846.8 8860882923 67603.2 5484933292 41846.8
gene_window_agg <- create_seacell_aggregates(tad_scores, seacells)
gene_window_corr <- rowwise_correlations(seacell_rna_agg, gene_window_agg,
                                         name = "Gene window around TSS")

gene_window_corr[[2]]

ggplot() +
  geom_point(aes(y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                 x =gene_window_corr[[1]]))  +
  geom_density_2d_filled(aes(y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])],
                             x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_archr[[1]][names(gene_window_corr[[1]])], 
                color = "red")) +
  theme(legend.position = "None")  +
  labs(x = "Correlation between gene expression and p2g activity scores, tad boundary",
        y = "Correlation between gene expression and ArchR gene activity scores", 
       title = "Peak-to-gene links within tad boundaries")

ggplot() +
  geom_point(aes(y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                 x =gene_window_corr[[1]]))  +
  geom_density_2d_filled(aes(y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])],
                             x = gene_window_corr[[1]]), alpha = 0.5) +
  geom_line(aes(x = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                y = seacell_corr_p2g[[1]][names(gene_window_corr[[1]])], 
                color = "red")) +
  theme(legend.position = "None")  +
  labs(x = "Correlation, tad boundaries",
        y = "Correlation, all p2g links ", 
       title = "Peak-to-gene links within tad boundaries vs. all links")

Adapted Archr Gene Activity Score function

ArchR provides a function to compute gene activity scores based on accessibility in the regions around the gene. For this a tile matrix is used. This tile matrix is a matrix where the genome is divided into bins of 500bp. If there is a Tn5 insertion in a bin the entry will be 1, if there is no insertion the entry will be 0. Importantly, they compared their function to 52 other functions and found their own function to be the best performing.

Here I tried to better understand how this function works and changed the source code of the ArchR function to also take peak matrix as input and compute the gene activity based on peaks, rather than based on tiles. Additionally, I adapted the funciton in a way such that it takes tad boundaries as input and uses all peaks which are within the same tad boundary as a gene to compute the activity scores.

There are two different options for computing gene activity scores in ArchR. First, we can use the TSS and create a gene window around it (+/- 100kp of TSS). All insertions found within tiles within this gene window will be accumulated for the gene activity scores. If we set the option ‘useGeneBoundaries=TRUE’ then we will make sure that no regions overlap between any two genes. If the gene window of one gene overlaps with the gene window of another gene, those tiles are not considered anymore. The disadvantage of this approac is that genes can be very large (>100bp), meaning that in some cases the 100kp extension downstream of the TSS would not even contain the entire gene body.

Second, we can use the entire gene body and extend the gene window beyond the start and end coordinates of the gene body. Importantly, the gene body is extended 5kb upstream of the TSS, to also include the promoter region. Using the entire gene body instead of only the TSS can be achieved by setting ‘useTSS=FALSE’. In this approach the gene window is created by extending -100kb upstream of the TSS -5kb and +100kb downstream of the gene end coordinate. This way, the entire gene body will be included in the gene window. An unwanted consequence of this might be that very large genes could bias the gene activity scores. Therefore ArchR introduces a weight for the inverse of the gene body size according to:

\(w = \frac{1}{gene size}\) with \(w\) being the inverse of the gene size. $

geneRegions\(geneWeight <- 1 + m * (geneScaleFactor - 1) / (max(m) - min(m))\)

Additionally, ArchR uses a distance weight. Farther away tiles/peaks are less likely to interact with a TSS than closer tiles/peaks. If the first approach, using only the TSS, the distance weights are computed as follows:

\(weight = e^{-(abs(distTSS/5000))}\) with \(distTSS\) being the distance from the TSS. This way the weights decay exponentially with distance. The constant value of \(5000\) is a parameter which could be optimized for different genes or datasets, but here we will keep it constant.

In case the entire gene body is used, the distance weights are kept constant for all tiles/peaks within the gene body and only decay beyond the gene body.

\(weight = \begin{cases} if (-5kb from TSS, TTS): 1 + e^{-1} \\ else: e^{-abs(distGB/5000) + e^{-1}} \end{cases}\)

ArchR Gene Activity Scores using TAD boundaries

Instead of using a +/-100kb window around the gene body, in the adapted function all peaks which are within the same TAD boundary as the gene of interest are considered for the activity score of that gene. The distance weight with c = 5000 is kept the same as for the default ArchR function. As can be seen below, extending the gene window to TAD boundaries yields very similar results compared to the default ArchR function.

proj <- loadArchRProject("12_Copy1/")

# proj <- addTADGeneScoreMatrix(
#   proj,
#   genes = getGenes(proj),
#   peaks = getPeakSet(proj),
#   tadBoundaries = tad_boundaries,
#   geneModel = "exp(-abs(x)/5000) + exp(-1)",
#   matrixName = "GeneScoreMatrix",
#   extendUpstream = c(1000, 100000),
#   extendDownstream = c(1000, 100000),
#   geneUpstream = 5000, #New Param
#   #geneDownstream = 0, #New Param
#   useGeneBoundaries = FALSE,
#   useTSS = FALSE, #New Param
#   extendTSS = FALSE,
#   tileSize = 500,
#   ceiling = 4,
#   geneScaleFactor = 5, #New Param
#   scaleTo = 10000,
#   excludeChr = c("chrY", "chrX", "chrM"),
#   blacklist = getBlacklist(proj),
#   threads = 1,
#   parallelParam = NULL,
#   subThreading = TRUE,
#   force = TRUE,
#   logFile = createLogFile(".addTADGeneScoreMat"))

scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")
score_mat <- assays(scores)[[1]]
rownames(score_mat) <- rowData(scores)$name


#saveRDS(scores, "tad_scores")
ggplot() +
  geom_histogram(aes(x = rowSums(score_mat)), bins = 200)
# compute aggregates of ArchR gene activity score matrix
default_archr <- create_seacell_aggregates(archr_scores_mat,
                                           seacells)
# compute aggregates for tad boundary ArchR gene activity score matrix
tad_archr <- create_seacell_aggregates(score_mat, seacells)
# compute aggregates of gene expression matrix
rna_hvg <- create_seacell_aggregates(expr_sub, seacells)

# correlation between gene expression values and default Archr gene activity scores
default_archr_corr <- rowwise_correlations(rna_hvg, default_archr, 
                                           "ArchR gene activity scores, SEAcells")
# correlation between gene expression and TAD boundary gene activity scores
tad_corr <- rowwise_correlations(rna_hvg, tad_archr, "ArchR gene activity scores within TAD boundaries, SEACells")

cowplot::plot_grid(default_archr_corr[[2]], tad_corr[[2]], ncol = 2)

ggplot() +
  geom_point(aes(x = tad_corr[[1]], y = default_archr_corr[[1]][names(tad_corr[[1]])])) +
  geom_density_2d_filled(aes(x = tad_corr[[1]], 
                             y = default_archr_corr[[1]][names(tad_corr[[1]])]),
                         alpha = .5) +
  geom_line(aes(x = default_archr_corr[[1]], y = default_archr_corr[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expression & ArchR TAD boundary scores",
        title = "Restricting ArchR scores to within TAD boundaries",
        y = "Correlation gene expression & ArchR gene activity scores")

TAD boundares E7.5

Since the TAD boundaries used here, are from gastrulation day E7.5. For the later time points no TAD boundaries are available. Therefore, in the following I will check if the results improve in comparison to the default ArchR function when using only data from E7.5. Since during gastrulation TAD boundaries might still be very dynamic the improving effect of TAD boundaries could be diluted by later time points in the data.

What are th genes which get zero activity scores? Do they lie outside the TAD boundaries?

e75_meta <- colData(scores) %>% as.data.frame() %>%
  filter(Sample %in% c("E7.5_rep1", "E7.5_rep2")) %>% 
  rownames_to_column("cell")
mat_75 <- score_mat[rownames(score_mat) %in% rownames(expr_sub), e75_meta$cell]
seacells_sub <- seacells %>% filter(index %in% colnames(mat_75)) 

# compute aggregates of ArchR gene activity score matrix
default_archr <- create_seacell_aggregates(archr_scores_mat[rownames(archr_scores_mat) %in%
                                                              rownames(expr_sub), 
                                                            e75_meta$cell],
                                           seacells_sub)
# compute aggregates for tad boundary ArchR gene activity score matrix
tad_archr <- create_seacell_aggregates(mat_75, seacells_sub)
# compute aggregates of gene expression matrix
rna_hvg <- create_seacell_aggregates(expr_sub[, e75_meta$cell], seacells_sub)

# correlation between gene expression values and default Archr gene activity scores
default_archr_corr <- rowwise_correlations(rna_hvg, default_archr, 
                                           "ArchR gene activity scores, SEAcells")
# correlation between gene expression and TAD boundary gene activity scores
tad_corr <- rowwise_correlations(rna_hvg, tad_archr, "ArchR gene activity scores within TAD boundaries, SEACells")

cowplot::plot_grid(default_archr_corr[[2]], tad_corr[[2]], ncol = 2)

ggplot() +
  geom_point(aes(x = tad_corr[[1]], y = default_archr_corr[[1]][names(tad_corr[[1]])])) +
  geom_density_2d_filled(aes(x = tad_corr[[1]], 
                             y = default_archr_corr[[1]][names(tad_corr[[1]])]),
                         alpha = .5) +
  geom_line(aes(x = default_archr_corr[[1]], y = default_archr_corr[[1]]), col = "red") +
  theme(legend.position = "None")  +
  labs(x = "Correlation gene expression & ArchR TAD boundary scores",
        title = "Restricting ArchR scores to within TAD boundaries",
        y = "Correlation gene expression & ArchR gene activity scores")

What are the genes which get zero correlation with gene expression?

There are 8 genes which get zero correlation values between gene activity scores and gene expression. This is, because they get zero activity scores in all cells. However, the same genes are expressed to certain levels according to the gene expression matrix. Two of the genes also get zero activity scores in the default ArchR function (Prl2c3, Gsdmc4). The reason for is not immediately clear, since as long as there are peaks in a gene window, the distance weight will at least be 0.36 accorindg to the formula. One reason for zero values could be that these genes lie outside TAD boundaries wich is in fact the case for four out of 8 genes.

What is the explanation why Lyz2 and Gm13547 get activity scores of zero?

zero_genes <- names(tad_corr[[1]][tad_corr[[1]] == 0])

zero_mat <- score_mat[zero_genes, ]
rowSums(zero_mat) 


# check the default ArchR scores for these genes
rowSums(archr_scores_mat[zero_genes, ])

# check the gene expression coutns for these genes
rowSums(expr_mat[zero_genes,])


p2g_pos <- p2g %>% as.data.frame() %>% filter(Correlation > 0) %>%
  unite(link, idxRNA, idxATAC, sep = "%", remove = FALSE)

gene_anno_all <- rowData(gene_expr) %>% as.data.frame() %>%
  mutate(idxRNA = seq(nrow(.))) %>% 
  filter(idxRNA %in% p2g_pos$idxRNA) %>%
  mutate(strand = ifelse(strand == 1, "+", "-")) %>%
  mutate(start_coord = ifelse(strand == "+", start, end)) %>% 
  rename(gene = name) #%>% GRanges()

# subset atac granges & get middle of each peak
pos_atac_granges_all <- metadata(p2g)[[1]]  %>% 
  as.data.frame() %>%
  mutate(idxATAC = seq(nrow(.))) %>% 
  # group_by(seqnames) %>%
  # mutate(idx = seq_along(seqnames)) %>% 
  # ungroup %>%
  #tidyr::unite(chr_idx, seqnames, idx, remove = FALSE, sep = "_") %>% 
  filter(idxATAC %in% p2g_pos$idxATAC) %>% 
  mutate(middle = start + 300) #%>% GRanges() 



# combine the three dataframes
p2g_join_all <- left_join(p2g_pos, as.data.frame(pos_atac_granges_all),
                      by = "idxATAC")
p2g_join_all <- left_join(p2g_join_all, as.data.frame(gene_anno_all),
                      by = "idxRNA", suffix = c(".atac", ".rna"))


p2g_join_all <- p2g_join_all %>% 
  mutate(distance = abs(start_coord - middle))



  # find overlapping peaks and gene window in chromosome-aware fashion
tad_overlaps_genes <- (findOverlaps(gene_anno_all %>% GRanges(), 
                                              tad_boundaries))


# get all genes which are found within tad boudnaries
gene_anno_within_tad <- gene_anno_all[queryHits(tad_overlaps_genes),]


# Lets examine the genes which are found within tad boundaries, but
# get an activity score of zero nevertheless
gene_anno_within_tad %>% filter(gene %in% zero_genes)


gene_name = "Lyz2"
chr_name = "chr2"
chrx <- tad_boundaries %>% as.data.frame() %>% filter(seqnames == chr_name) %>%GRanges()
hits <- findOverlaps(gene_anno_all %>% filter(gene == gene_name) %>% GRanges(),  chrx)
start_tad <- start(chrx[subjectHits(hits),])
end_tad <- end(chrx[subjectHits(hits),])
start_gene <- start(gene_anno_all %>% filter(gene == gene_name) %>% GRanges())
end_gene <- end(gene_anno_all %>% filter(gene == gene_name) %>% GRanges())
print(paste0("Out of ", length(zero_genes), " genes,  ",  length(zero_genes[zero_genes %in% gene_anno_within_tad$gene]) , " genes are found within tad boundaries, while the rest are not."))
pos_atac_granges_all %>% as.data.frame() %>% filter(seqnames == chr_name) %>%
  filter(start > start_tad & end < end_tad)

# 
# zero_genes
# 
# idx <- (gene_anno_all %>% filter(gene %in% zero_genes))$idxRNA
# 
# idx %in% gene_anno_all[tad_overlaps_genes$queryHits,

ArchR Gene Activity Scores using gene body

ArchR Gene Activity Scores using gene body


#saveArchRProject(ArchRProj = proj, outputDirectory = "12_Copy4/", load = FALSE)
loadArchRProject("12_activity_scores_gene_body_peaks/")

proj <- addKathiGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  peaks = getPeakSet(proj),
  geneModel = "exp(-abs(x)/5000) + exp(-1)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = FALSE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addKathiGeneScoreMat"))


scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name


# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rowData(scores)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_gene_body_peak_based", X_name = "scores")

Correlating gene expression with activity scores:

archr_gene_body_agg <- knn_aggregates(scores_mat, cell_agg_list)

gene_body_knn <- rowwise_correlations(rna_agg, archr_gene_body_agg, "ArchR gene activity scores based on peak matrix, using gene body")


cowplot::plot_grid(archr_knn[[2]], gene_body_knn[[2]], ncol = 2)

p1 <- ggplot() + geom_density_2d_filled(aes(x = gene_body_knn[[1]], 
                                      y = archr_knn[[1]]), alpha = .5) +
  geom_point(aes(x = gene_body_knn[[1]], y = archr_knn[[1]])) +
  geom_line(aes(x = gene_body_knn[[1]], y = gene_body_knn[[1]]), col = "red") +
  theme(legend.position = "None") 

ArchR Gene Activity Scores using TSS, no gene body

ArchR Gene Activity Scores using TSS, no gene body


proj <- loadArchRProject("12_activity_scores_TSS_tiles/")

proj <- addGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  geneModel = "exp(-abs(x)/5000)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = TRUE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addGeneScoreMatrix"))


scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name


# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rowData(scores)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_tss", X_name = "scores")

ArchR gene activity scores computed using TSS, no gene body and PeakMatrix instead of TileMatrix

ArchR gene activity scores computed using TSS, no gene body and PeakMatrix instead of TileMatrix

proj <- loadArchRProject("12_activity_scores_TSS_peaks/")

proj <- addKathiGeneScoreMatrix(
  proj,
  genes = getGenes(proj),
  peaks = getPeakSet(proj),
  geneModel = "exp(-abs(x)/5000)",
  matrixName = "GeneScoreMatrix",
  extendUpstream = c(1000, 100000),
  extendDownstream = c(1000, 100000),
  #geneUpstream = 5000, #New Param
  #geneDownstream = 0, #New Param
  useGeneBoundaries = TRUE,
  useTSS = TRUE, #New Param
  extendTSS = FALSE,
  tileSize = 500,
  ceiling = 4,
  geneScaleFactor = 5, #New Param
  scaleTo = 10000,
  excludeChr = c("chrY", "chrM"),
  blacklist = getBlacklist(proj),
  threads = 1,
  parallelParam = NULL,
  subThreading = TRUE,
  force = TRUE,
  logFile = createLogFile(".addKathiGeneScoreMat"))

scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")

scores_mat <- assays(scores)[[1]]
rownames(scores_mat) <- rowData(scores)$name

#
# sce <- SingleCellExperiment(list(scores=scores_mat),
#                           rowData = as.data.frame(rownames(scores_mat)),
#                           colData = as.data.frame(colnames(scores_mat)))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_scores_peak_based", X_name = "scores")



# sce <- SingleCellExperiment(list(p2g_mat = p2g_mat))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/p2g_mat_250kb",
#           X_name = "p2g_mat")

# 
# 
# sce <- SingleCellExperiment(list(peak_mat = peak_mat))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/peak_mat",
#           X_name = "peak_mat")


# cp_names <- colnames(colData(gene_expr))
# cp_names[20] <- "celltypes"
# colnames(colData(gene_expr)) <- cp_names

sce <- SingleCellExperiment(list(genes = expr_mat),
                           #rowData = as.data.frame(rownames(gene_expr)),
                           colData = as.data.frame(colData(gene_expr)))

# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/gene_expr_mat",
#           X_name = "genes")
# 
# 
# #p2g_mat_norm <- p2g_mat / rowSums(p2g_mat)
# scores <- p2g_mat %*% peak_mat
# scores <- t(t(scores) / colSums(scores))
# stopifnot(any(is.na(scores)) == FALSE)
# scores@x <- pmin(1e9, exp(scores@x) - 1)
# 
# 
# 
# sce <- SingleCellExperiment(list(investigation = investigation))
# 
# writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/investigation_scores",
#           X_name = "investigation")





# latent embedding
emb <- getReducedDims(
  ArchRProj = proj,
  reducedDims = "atac_LSI_100000",
  returnMatrix = TRUE,
  dimsToUse = 1:30,
  scaleDims = NULL,
  corCutOff = 0.75
)
dim(emb)


sce <- SingleCellExperiment(list(embedding = emb))

writeH5AD(sce, "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/p2g_gene_activity_scores/archr_lsi_embedding",
          X_name = "embedding")

Granja JM, Pierce SE, Corces MR. 2021. ArchR Is a Scalable Software Package for Integrative Single-Cell Chromatin Accessibility Analysis. Nat Genet. Vols. 53(3):403-411. doi: 10.1038/s41588-021-00790-6.

Persad, Sitara, Zi-Ning Choo, Christine Dien, Ignas Masilionis, Ronan Chaligné, Tal Nawy, Chrysothemis C Brown, Itsik Pe’er, Manu Setty, and Dana Pe’er. 2022. “SEACells: Inference of Transcriptional and Epigenomic Cellular States from Single-Cell Genomics Data.” bioRxiv. Cold Spring Harbor Laboratory. https://doi.org/10.1101/2022.04.02.486748.

Zuin J., Zhan Y., Roth G. 2022. “Nonlinear Control of Transcription Through Enhancer-Promoter Interactions.” Nature. https://doi.org/10.1038/s41586-022-04570-y.

LS0tCnRpdGxlOiAiSW52ZXN0aWdhdGluZyBwMmdfbWF0IgpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gRkFMU0UpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEiKQpzZXR3ZCgiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YSIpCnNldC5zZWVkKDEpCmBgYAoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CgpsaWJyYXJ5KEFyY2hSKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKbGlicmFyeSh6ZWxsa29udmVydGVyKQpsaWJyYXJ5KGR0d2NsdXN0KQp9KQpgYGAKCmBgYHtyfQpwcm9qIDwtIGxvYWRBcmNoUlByb2plY3QoIjExX2FkZGVkX1JpY2FyZHNfcGVha3NfcDJnX2VudGlyZV9jaHJvbW9zb21lIiwgc2hvd0xvZ28gPSBGQUxTRSkKI3NhdmVBcmNoUlByb2plY3QocHJvaiwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvMTFfYWRkZWRfUmljYXJkc19wZWFrc19wMmdfZW50aXJlX2Nocm9tb3NvbWUiKQoKYGBgCgojIFAyRy1saW5rIG1hdHJpeCAKCkluIG9yZGVyIHRvIGdldCBnZW5lIHJlZ3VsYXRvcnkgbGlua3MsIG9uZSBjYW4gY29tcHV0ZSBhIHNpbXBsZSBjb3JyZWxhdGlvbgpiZXR3ZWVuIGFjY2Vzc2libGUgcGVha3MgYW5kIGdlbmUgZXhwcmVzc2lvbiwgaW4gb3JkZXIgdG8gZmluZCBwZWFrcyB3aG9zZSBhY3Rpdml0eQppcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIGV4cHJlc3Npb24gb2YgYSBjZXJ0YWluIGdlbmUuIFRoZXNlIGFyZSBwb3RlbnRpYWwgCmVuaGFuY2VycyBvZiBhIGdlbmUuIFNpbmNlIHNpbmdsZSBjZWxsIGRhdGEgaXMgdmVyeSBzcGFyc2UsIHRoZSBjb21tb24gd2F5IHRvIApjb21wdXRlIGNvcnJlbGF0aW9zbiBpcyBieSBhZ2dyZWdhdGluZyBhY2Nlc3NpYmlsaXR5IGFuZCBnZW5lIGV4cHJlc3Npb24gZGF0YQphY3Jvc3MgY2VsbCBhZ2dyZWdhdGVzLiBJbiBBcmNoUiB0aGlzIGlzIGRvbmUgYnkgc2FtcGxpbmcgNTAwIGNlbGxzIGZyb20gdGhlIAplbnRpcmUgZGF0YXNldCBhbmQgZmluZGluZyB0aGUgNTAgbmVhcmVzdCBuZWlnaGJvcnMgb2YgdGhlc2UgY2VsbHMuIFRoZXNlIGNlbGwKYWdncmVnYXRlcyB0aGVyZWZvcmUgcmVwcnNlbnQgZ3JvdXBzIG9mIHNpbWlsYXIgY2VsbHMgYW5kIGNhbiBiZSB1c2VkIHRvIGNvbXB1dGUKY29ycmVsYXRpb25zLiAKCk5vdGFibHksIGZvciBjb21wdXRpbmcgbGlua3Mgd2l0aGluIGEgY2VydGFpbiBkaXN0YW5jZSBvbiB0aGUgY2hyb21vc29tZSwgQXJjaFIKZG9lcyBub3QgdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gdGhlIHN0cmFuZCBvcmllbnRhdGlvbiwgYnV0IGNvbXB1dGVzIHRoZSAKZGlzdGFuY2UgYmV0d2VlbiB0aGUgInN0YXJ0IiBjb29yZGluYXRlIGFuZCB0aGUgcGVhayBtaWRkbGUgY29vcmRpbmF0ZS4gSG93ZXZlciwKb24gdGhlIG1pbnVzIHN0cmFuZCB0aGUgVFNTIGlzIHRoZSAiZW5kIiBjb29yZGluYXRlLiBGb3IgdGhlIGNvcnJlbGF0aW9ucyB0aGlzCmlzIG5vdCBpbXBvcnRhbnQsIGJ1dCBpbiBteSBjb21wdXRhdGlvbnMgSSB3aWxsIHVzZSB0aGUgVFNTIGNvb3JkaW5hdGUgaW4KYSBzdHJhbmQtYXdhcmUgZmFzaGlvbi4KCgpCYXNlZCBvbiB0aGVzZSBwdXRhdGl2ZSBwZWFrLXRvLWdlbmUgbGlua3MsIGl0IGlzIHBvc3NpYmxlIHRvIGNvbXB1dGUgZ2VuZSBhY3Rpdml0eQpzY29yZXMuIElmIHRoZXNlIHNjb3JlcyByZWNhcGl0dWxhdGUgZ2VuZSBleHByZXNzaW9uIHdlbGwsIHRoaXMgaXMgYSAKdmFsaWRhdGlvbiBvZiB0aGUgbGlua3MuIE5ldmVydGhlbGVzcywgaXQgaXMgZXhwZWN0ZWQgdGhhdCBnZW5lIGFjdGl2aXR5IHNjb3Jlcwpjb3JyZWxhdGUgaGlnaGx5IHdpdGggZ2VuZSBleHByZXNzaW9uLCBzaW5jZSB0aGUgcGVha3MgdXNlZCBmb3IgdGhlIGNvbXB1dGF0aW9uIAphcmUgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgZ2VuZXMgcGVyIGRlZmluaXRpb24uIEluIHRoZSBmb2xsb3dpbmcgeW91IHdpbGwgZmluZCBhIGZ1bmN0aW9uIHRvIGNvbXB1dGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMgZnJvbSBwZWFrLXRvLWdlbmUgbGlua3MsIGFkcGF0ZWQgZnJvbSAKQ2ljZXJvLCB3aGVyZSBnZW5lIGFjdGl2aXQgc2NvcmVzIGFyZSBjb21wdXRlZCBmcm9tIGNvLWFjY2Vzc2libGUgcGVha3MuCgpGdXJ0aGVybW9yZSwgc2luY2UgcGVha3Mgd2hpY2ggYXJlIGZhcnRoZXIgYXdheSBmcm9tIGEgZ2VuZSBvbiB0aGUgZ2Vub21lIGFyZSBsZXNzIGxpa2VseSAKdG8gcmVndWxhdGUgdGhpcyBnZW5lLCBpdCBpcyBjb21tb24gdG8gdXNlIGRpc3RhbmNlIHdlaWd0aHMgdG8gcGVuYWxpemUgcGVha3Mgd2hpY2gKYXJlIGhpZ2hseSBjb3JyZWxhdGVkLCBidXQgZGlzdGFudC4gSG93ZXZlciwgSSBvYnNlcnZlZCB0aGF0IHVzaW5nIGRpc3RhbmNlIHdlaWd0aHMKZGVjcmVhc2VzIHRoZSBjb3JyZWxhdGlvbiB3aXRoIGdlbmUgZXhwcmVzc2lvbiwgd2l0aCBsZXNzIHN0ZWVwIGRlY2F5IHJhdGVzIApyZXN1bHRpbmcgaW4gYmV0dGVyIGdlbmUgYWN0aXZpdHkgc2NvcmVzLiBUaGlzIHNob3dzIHRoYXQgdGhlIGRpc3RhbmNlIHdlaWdodHMgCmxlYWQgdG8gYSBsb3Qgb2YgemVybyB2YWx1ZXMgd2hlbiBtdWx0aXBsaWVkIHdpdGggdGhlIGNvcnJlbGF0aW9uIHZhbHVlcy4gU3RpbGwsCmJpb2xvZ2ljYWxseSB2ZXJ5IGRpc3RhbnQgcGVha3MgYXJlIHByb2JhYmx5IG5vdCBjb3JyZWxhdGVkIHdpdGggYSBwcm9tb3RlciwgYmVjYXVzZSAKdGhleSBhcmUgaW50ZXJlYWN0aW5nLCBidXQgbW9yZSBsaWtlbHksIGFyZSBhcmJpdHJhcnkgY29ycmVsYXRpb25zLiBGaW5kaW5nIGEgCmdvb2QgdHJhZGUtb2ZmIGJldHdlZW4gY29uc2lkZXJpbmcgY29ycmVsYXRpb25zIGFjcm9zcyBsYXJnZSBkaXN0YW5jZXMsIGJ1dCBhbHNvCnVzaW5nIHByaW9yIGtub3dsZWRnZSBhYm91dCB0aGUgYmlvbG9neSBhbmQgcmVzdHJpY3RpbmcgdGhlIGxpbmtzIHRvIGEgY2VydGFpbiAKd2luZG93IGlzIG5vbi10cml2aWFsLiBUaGUgY29ycmVjdCBkaXN0YW5jZSBkZWNheSByYXRlICBwcm9iYWJseSBkZXBlbmRzIG9uIGVhY2ggaW5kaXZpZHVhbCBnZW5lIGFuZCBtaWdodCBkaWZmZXIgYWNyb3NzIGNlbGx0eXBlcy4KCllldCBhbm90aGVyIGFwcHJvYWNoIHdvdWxkIGJlIHRvIHVzZSBvbmx5IHBlYWtzLCB3aGljaCBhcmUgd2l0aGluICsvLSAxMDBrYiBvZiB0aGUKVFNTIG9mIGEgZ2VuZSwgdGhlcmVieSwgcmVtb3ZpbmcgYW55IHBlYWtzIHdoaWNoIGFyZSBmYXIgYXdheS4gVGhpcyBpcyBzaW1pbGFyIHRvIAp0aGUgYXBwcm9hY2ggaW4gQXJjaFIuIEhlcmUsIHRoZSBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmb3IgZWFjaCBnZW5lIGFyZSBjb21wdXRlZApiYXNlZCBvbiBhbGwgcGVha3Mgd2hpY2ggYXJlIHdpdGhpbiArLy0gMTAwYnAgb2YgdGhlIFRTUyBvZiB0aGUgZ2VuZS4gQXMgeW91IAp3aWxsIHNlZSBpbiB0aGUgZm9sbG93aW5nIHBsb3RzIHVzaW5nIHRoaXMgYXBwcm9hY2ggbGVhZHMgdG8gdmVyeSBoaWdoIGNvcnJlbGF0aW9ucwpiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgZ2VuZSBhY3Rpdml0eSBzY29yZXMuIENvbXB1dGluZyB0aGUgc2NvcmVzIGJhc2VkIG9uIApwZWFrLXRvLWdlbmUgbGlua3Mgb2ZmZXJzIG9ubHkgYSBtaW5vciBpbXByb3ZlbWVudC4gCgpUaGUgbWFpbiBwdXJwb3NlIG9mIHRoZSBlbnRpcmUgZXhjZXJjaXNlIHdhcyB0byBiZSBhYmxlIHRvIGNvbXBhcmUgdGhlIGdvb2RuZXNzIApvZiB0aGVzZSBsaW5rcyB0byBsaW5rcyBvYnRhaW5lZCB1c2luZyBzY0RvUmkuIFRoaXMgcmVsYXRpb25zaGlwIHdpbGwgaGF2ZSB0byBiZSAKZXhwbG9yZWQgZnVydGhlci4gCgpgYGAje3J9CnByb2ogPC0gYWRkUGVhazJHZW5lTGlua3MoQXJjaFJQcm9qID0gcHJvaiwKICByZWR1Y2VkRGltcyAgPSAiYXRhY19MU0lfMTAwMDAwIiwKICB1c2VNYXRyaXggPSAiR2VuZUV4cHJlc3Npb25NYXRyaXgiLAogIG1heERpc3QgPSA0MDAwMDAwMDAsCiAgdmVyYm9zZSA9IFRSVUUKICApCgpwMmcgPC0gZ2V0UGVhazJHZW5lTGlua3MoCiAgQXJjaFJQcm9qID0gcHJvaiwKICBjb3JDdXRPZmYgPSAtMSwKICByZXNvbHV0aW9uID0gMSwKICBGRFJDdXRPZmYgPSAxZS0wNCwKICB2YXJDdXRPZmZBVEFDID0gLjI1LAogIHZhckN1dE9mZlJOQSA9IC4yNSwgCiAgcmV0dXJuTG9vcHMgPSBGQUxTRQopCmBgYAoKCmBgYHtyfQojc2F2ZVJEUyhwMmcsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL1JtZHMvcGVhazJnZW5lX2xpbmtzX2VudGlyZV9jaHJvbW9zb21lXzI1XzA0XzIwMjIiKQpwMmcgPC0gcmVhZFJEUyggIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvUm1kcy9wZWFrMmdlbmVfbGlua3NfZW50aXJlX2Nocm9tb3NvbWVfMjVfMDRfMjAyMiIpCmBgYAoKUmVhZCBpbiB0aGUgcGVhayBhY2Nlc3NpYmlsaXR5IG1hdHJpeCBhbmQgdGhlIGdlbmUgZXhwcmVzc2lvbiBtYXRyaXg6CgpgYGB7cn0KIyBnZXQgcGVhayBtYXRyaXgKcGVha3MgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgdXNlTWF0cml4ID0gIlBlYWtNYXRyaXgiLCBiaW5hcml6ZSA9IEZBTFNFKQpwZWFrX21hdCA8LSBhc3NheXMocGVha3MpW1sxXV0KCiMgcmVhZCBpbiBnbmUgZXhwcmVzc3Npb24gbWF0cml4CmdlbmVfZXhwciA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzZU1hdHJpeCA9ICJHZW5lRXhwcmVzc2lvbk1hdHJpeCIpCmV4cHJfbWF0IDwtIGFzc2F5cyhnZW5lX2V4cHIpW1sxXV0Kcm93bmFtZXMoZXhwcl9tYXQpIDwtIHJvd0RhdGEoZ2VuZV9leHByKSRuYW1lCgojIHJlYWQgaW4gYXJjaHIgZ2VuZSBhY3Rpdml0eSBzY29yZXMKYXJjaHJfc2NvcmVzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIHVzZU1hdHJpeCA9ICJHZW5lU2NvcmVNYXRyaXgiKQoKY3BfbmFtZXMgPC0gY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKQpjcF9uYW1lc1syMF0gPC0gImNlbGx0eXBlcyIKY29sbmFtZXMoY29sRGF0YShhcmNocl9zY29yZXMpKSA8LSBjcF9uYW1lcwoKYXJjaHJfc2NvcmVzX21hdCA8LSBhc3NheXMoYXJjaHJfc2NvcmVzKVtbMV1dCnJvd25hbWVzKGFyY2hyX3Njb3Jlc19tYXQpIDwtIHJvd0RhdGEoYXJjaHJfc2NvcmVzKSRuYW1lCmBgYAoKV2Ugd2lsbCBvbmx5IHVzZSBwZWFrcyBsaW5rZWQgdG8gaGlnaGx5IHZhcmlhYmxlIGdlbmVzIHRvIGNvbXB1dGUgZ2VuZQphY3Rpdml0eSBzY29yZXMuCgpgYGB7cn0KaHZnX2xpc3QgPC0gcmVhZC50YWJsZSgianVweXRlcl9ub3RlYm9va3MvaHZnX2xpc3QiLCBzZXAgPSAiLCIpJHgKCgojIGdldCBSTkEgaW5kZXggb2YgaHZnCm1ldGFfcm5hIDwtIHJvd0RhdGEoZ2VuZV9leHByKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBtdXRhdGUocm93X2luZGV4ID0gc2VxKG5yb3coLikpKQppZHggPC0gKG1ldGFfcm5hICU+JSBmaWx0ZXIobmFtZSAlaW4lIGh2Z19saXN0KSkkcm93X2luZGV4CgpleHByX3N1YiA8LSBleHByX21hdFtpZHgsIF0KYGBgCgpgYGB7cn0Kc2VhY2VsbHMgPC0gcmVhZF9jc3YoImp1cHl0ZXJfbm90ZWJvb2tzL1NFQUNlbGxfZmlsZXMvU0VBQ2VsbF9hc3NpZ25tZW50IikKYGBgCgoKYGBge3J9CmxpbmtzIDwtIHAyZyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBmaWx0ZXIoQ29ycmVsYXRpb24gPiAwLjIpICU+JSAKICBmaWx0ZXIoaWR4Uk5BICVpbiUgaWR4KSAKCnN0b3BpZm5vdChhbGwobGlua3MkQ29ycmVsYXRpb24gPiAwKSkKYGBgCgoKCkNyZWF0ZSBhIHAyZyBsaW5rIG1hdHJpeAoKYGBge3J9CnAyZ19tYXQgPC0gc3BhcnNlTWF0cml4KGkgPSBsaW5rcyRpZHhSTkEsCiAgICAgICAgICAgICBqID0gbGlua3MkaWR4QVRBQywKICAgICAgICAgICAgIHg9IGxpbmtzJENvcnJlbGF0aW9uLCAKICAgICAgICAgICAgIGRpbXMgPSBjKGRpbShleHByX21hdClbMV0sCiAgICAgICAgICAgICBkaW0ocGVha19tYXQpWzFdKSkKCnJvd25hbWVzKHAyZ19tYXQpIDwtIHJvd0RhdGEoZ2VuZV9leHByKSRuYW1lCgoKcm93bmFtZXMocGVha19tYXQpIDwtIHNlcS5pbnQoZGltKHBlYWtfbWF0KVsxXSkKY29sbmFtZXMocDJnX21hdCkgPC0gc2VxLmludChkaW0ocGVha19tYXQpWzFdKQpgYGAKCgoKRmlsdGVyIGFuZCBwcmVwYXJlIHBlYWsgbWF0cml4IGFuZCBwMmcgbGlua3MgbWF0cml4OgoKYGBge3J9CiMgcmVtb3ZlIGNvbHVtbnMgb2YgcGVha3Mgd2hpY2ggYXJlIG5vdCBsaW5rZWQgdG8gYW55IHBlYWsKcDJnX21hdF9zdWIgPC0gcDJnX21hdFssIGNvbFN1bXMocDJnX21hdCkgIT0gMF0KIyB1c2Ugb25seSBoaWdobHkgdmFyaWFibGUgZ2VuZXMKcDJnX21hdF9zdWIgPC0gcDJnX21hdF9zdWJbaHZnX2xpc3QsIF0KIyByZW1vdmUgYW55IGdlbmVzIHdoaWNoIGFyZSBub3QgbGlua2VkIHRvIGFueSBwZWFrCnAyZ19tYXRfc3ViIDwtIHAyZ19tYXRfc3ViW3Jvd1N1bXMocDJnX21hdF9zdWIpICE9IDAsIF0Kc3RvcGlmbm90KGFsbChyb3duYW1lcyhwMmdfbWF0X3N1YikgJWluJSBodmdfbGlzdCkpCnN0b3BpZm5vdChhbnkoaXMubmEocDJnX21hdF9zdWIpID09IEZBTFNFKSkKCiMga2VlcCBvbmx5IHBlYWtzIHdoaWNoIGFyZSBsaW5rZWQgdG8gZ2VuZXMgaW4gdGhlIGFjY2Vzc2liaWxpdHkgbWF0cml4CnBlYWtfbWF0X3N1YiA8LSBwZWFrX21hdFtjb2xuYW1lcyhwMmdfbWF0X3N1YiksIF0Kc3RvcGlmbm90KHJvd25hbWVzKHBlYWtfbWF0X3N1YikgPT0gY29sbmFtZXMocDJnX21hdF9zdWIpKQojc3RvcGlmbm90KGFueShpcy5uYShwZWFrX21hdF9zdWIpID09IEZBTFNFKSkKc3RvcGlmbm90KGRpbShwZWFrX21hdF9zdWIpWzFdID09IGRpbShwMmdfbWF0X3N1YilbMl0pCgpleHByX21hdF9zdWIgPC0gZXhwcl9tYXRbYXMudmVjdG9yKHJvd25hbWVzKHAyZ19tYXRfc3ViKSksIF0KYGBgCgoKCgoKCiMjIyBGdW5jdGlvbiB0byBjb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzCgpgYGB7cn0KZ2VuZV9hY3Rpdml0eV9zY29yZXMgPC0gZnVuY3Rpb24ocGVha19tYXQsIHAyZ19tYXQpIHsKICAjcGVha19tYXRfc3Vic2V0IDwtIHBlYWtfbWF0W2NvbG5hbWVzKHAyZ19tYXQpLCBdCiAgIyBub3JtYWxpemUgdGhlIHAyZyBtYXRyaXggYnkgdGhlIHRvdGFsIG51bWJlciBvZiBwZWFrcyBsaW5rZWQgdG8gZWFjaCBnZW5lCiAgcDJnX21hdCA8LSBwMmdfbWF0IC8gcm93U3VtcyhwMmdfbWF0KQogIHByaW50KHBhc3RlMCgibm9ybWFsaXplZCB0aGUgcDJnIG1hdHJpeCIpKQogIHN0b3BpZm5vdChhbnkoaXMubmEocDJnX21hdCkpID09IEZBTFNFKQogICMgTm93IHdlIGNhbiBjb21wdXRlIGEgd2VpZ2h0ZWQgc3VtIG9mIHBlYWsyZ2VuZSBjb3JyZWxhdGlvbnMgZm9yIGVhY2gKICAjIHBlYWsgYW5kIGdlbmUKICBzY29yZXMgPC0gcDJnX21hdCAlKiUgcGVha19tYXQKICBwcmludChwYXN0ZTAoIkNvbXB1dGVkIHdlaWdodGVzIHN1bSBvZiBwZWFrcyBmb3IgZWFjaCBnZW5lIGFuZCBjZWxsIikpCiAgIyBjcmVhdGUgYSBkYXRhZnJhbWUgZm9yIGNvbXB1dGluZyB0aGUgbGluZWFyIG1vZGVsCiAgbGluZWFyX21vZGVsX2RmIDwtIGRhdGEuZnJhbWUoY2VsbCA9IGNvbG5hbWVzKHNjb3JlcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9hY3Rpdml0eSA9IGNvbFN1bXMoc2NvcmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX3NpdGVzID0gY29sU3VtcyhwZWFrX21hdCkpCiAgIyBjb21wdXRlIGEgbGluZWFyIG1vZGVsCiAgYWN0aXZpdHlfbW9kZWwgPC0gc3RhdHM6OmxtKGxvZyh0b3RhbF9hY3Rpdml0eSkgfiBsb2codG90YWxfc2l0ZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGxpbmVhcl9tb2RlbF9kZikKICAjIGV4dHJhY3QgdGhlIGZpdHRlZCBtb2RlbAogIGxpbmVhcl9tb2RlbF9kZiRmaXR0ZWRfY3VydmUgPC0gZXhwKGFzLnZlY3RvcihwcmVkaWN0KGFjdGl2aXR5X21vZGVsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIikpKQogICMgY29tcHV0ZSBzaXplIGZhY3RvcnMgZnJvbSBmaXR0ZWQgbW9kZWwKICBzaXplX2ZhY3RvcnMgPC0gbWVhbihsaW5lYXJfbW9kZWxfZGYkZml0dGVkX2N1cnZlKSAvIGxpbmVhcl9tb2RlbF9kZiRmaXR0ZWRfY3VydmUKICAjIGNyZWF0ZSBkaWFnb25hbCBtYXRyaXggY29udGFpbmluZyB0aGUgc2l6ZSBmYWN0b3JzCiAgc2l6ZV9mYWN0b3JzX21hdCA8LSBNYXRyaXg6OkRpYWdvbmFsKHggPSBzaXplX2ZhY3RvcnMpCiAgI3Jvdy5uYW1lcyhzaXplX2ZhY3RvcnNfbWF0KSA8LSBsaW5lYXJfbW9kZWxfZGYkY2VsbAogICMgbm9ybWFsaXplIGJ5IGxpYnJhcnkgZGVwdGggc2l6ZSBmYWN0b3JzCiAgbm9ybV9zY29yZXMgPC0gTWF0cml4Ojp0KHNpemVfZmFjdG9yc19tYXQgJSolIE1hdHJpeDo6dChzY29yZXMpKQogIHByaW50KHBhc3RlMCgiTm9ybWFsaXplZCBmb3IgbGlicmFyeSBzaXplIikpCiAgIyBleHBvbmVudGlhdGUsIGJlY2F1c2UgUk5BIGNvdW50cyBhcmUgbG9nLW5vcm1hbGx5IGRpc3RyaWJ1dGVkCiAgbm9ybV9zY29yZXNAeCA8LSBwbWluKDFlOSwgZXhwKG5vcm1fc2NvcmVzQHgpIC0gMSkKICBwcmludChwYXN0ZTAoIkV4cG9uZW50aWF0ZWQgbWF0cml4IikpCiAgCiAgIyBmcmVlIHNvbWUgbWVtb3J5CiAgI3JtKHBlYWtfbWF0X3N1YnNldCkKICBybShhY3Rpdml0eV9tb2RlbCkKICBybShzY29yZXMpCiAgZ2MocmVzZXQgPSBUUlVFKQoKICAjIHNjYWxlIHdpdGggdG90YWwgYWN0aXZpdHkgc2NvcmVzIGFnYWluCiAgc2NhbGVfZmFjdG9ycyA8LSBNYXRyaXg6OkRpYWdvbmFsKHggPSAxL01hdHJpeDo6Y29sU3Vtcyhub3JtX3Njb3JlcykpCiAgcHJpbnQocGFzdGUwKCJEaXZpZGVkIGJ5IHRvdGFsIGFjdGl2aXR5IHRvIGdldCB2YWx1ZSBiZXR3ZWVuIHplcm8gYW5kIG9uZSIpKQogIAogIGZpbmFsX3Njb3JlcyA8LSBNYXRyaXg6OnQoc2NhbGVfZmFjdG9ycyAlKiUgTWF0cml4Ojp0KG5vcm1fc2NvcmVzKSkKCiAgcmV0dXJuKGZpbmFsX3Njb3JlcykKCn0KCmBgYAoKYGBge3J9CnAyZ19zY29yZXMgPC0gZ2VuZV9hY3Rpdml0eV9zY29yZXMocGVha19tYXRfc3ViLCBwMmdfbWF0X3N1YikKI3NhdmVSRFMocDJnX3Njb3JlcywgIkFyY2hSX3AyZ19iYXNlZF9nZW5lX2FjdGl2aXR5X3Njb3JlcyIpCmBgYAoKCgpUT0RPOiBBZGQgZnVuY3Rpb25zIGhlcmUsIGFkZCBBcmNoUiBhZ2dyZWdhdGVzIGFuZCBjb21wdXRlIGNvcnJlbGF0aW9ucyBhcyAKc2NhdHRlciAmIGRlbnNpdHkgcGxvdAoKIyBFeGFtcGxlIG9mIHAyZyBsaW5rcyB3aXRoaW4gMjUwa2IKCgpgYGB7cn0KY3BfbmFtZXMgPC0gY29sbmFtZXMoY29sRGF0YShnZW5lX2V4cHIpKQpjcF9uYW1lc1syMF0gPC0gImNlbGx0eXBlcyIKY29sbmFtZXMoY29sRGF0YShnZW5lX2V4cHIpKSA8LSBjcF9uYW1lcwoKI3Jvd25hbWVzKGV4cHJfbWF0KSA8LSByb3dEYXRhKGdlbmVfZXhwcikkbmFtZQpnZW5lcyA8LSBleHByX21hdFthcy52ZWN0b3Iocm93bmFtZXMocDJnX3Njb3JlcykpLCBdCgpzdG9waWZub3QoYW55KHJvd25hbWVzKGdlbmVzKSA9PSByb3duYW1lcyhwMmdfc2NvcmVzKSkpCgoKCiMgY3JlYXRlIG1hdHJpeCB0byBzdG9yZSBhZ2dyZWdhdGVzCmV4cHJfYWdnIDwtIG1hdHJpeChkYXRhID0gMCwgCiAgICAgICAgICAgICAgICAgICBucm93ID0gZGltKGdlbmVzKVsxXSwKICAgICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgodW5pcXVlKGNvbERhdGEoZ2VuZV9leHByKSRjZWxsdHlwZXMpKSwKICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzICA9IGxpc3Qocm93bmFtZXMocDJnX3Njb3JlcyksCiAgICAgICAgICAgICAgICAgICB1bmlxdWUoY29sRGF0YShnZW5lX2V4cHIpJGNlbGx0eXBlcykpKQoKCiMgZmlsbCBtYXRyaXgKZm9yIChjZWxsdHlwZSBpbiB1bmlxdWUoY29sRGF0YShnZW5lX2V4cHIpJGNlbGx0eXBlcykpewogIGJhcmNvZGVzIDwtIHJvd25hbWVzKGNvbERhdGEoZ2VuZV9leHByKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNlbGx0eXBlcyA9PSBjZWxsdHlwZSkpCiAgZXhwcl9hZ2dbLCBjZWxsdHlwZV0gPC0gcm93U3VtcyhnZW5lc1ssIGJhcmNvZGVzXSkKfQoKCgpwMmdfc2NvcmVfYWdnIDwtIG1hdHJpeChkYXRhID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSBkaW0ocDJnX3Njb3JlcylbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgodW5pcXVlKGNvbERhdGEoZ2VuZV9leHByKSRjZWxsdHlwZXMpKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KHJvd25hbWVzKHAyZ19zY29yZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcXVlKGNvbERhdGEoZ2VuZV9leHByKSRjZWxsdHlwZXMpKSkKCmZvciAoY2VsbHR5cGUgaW4gdW5pcXVlKGNvbERhdGEoZ2VuZV9leHByKSRjZWxsdHlwZXMpKXsKICBiYXJjb2RlcyA8LSByb3duYW1lcyhjb2xEYXRhKGdlbmVfZXhwcikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihjZWxsdHlwZXMgPT0gY2VsbHR5cGUpKQogIHAyZ19zY29yZV9hZ2dbLCBjZWxsdHlwZV0gPC0gcm93U3VtcyhwMmdfc2NvcmVzWywgYmFyY29kZXNdKQp9CmBgYAoKCgoKQ29ycmVsYXRpb25zIGJldHdlZW4gYWdncmVnYXRlZCBnZW5lIGV4cHJlc3Npb24gYW5kIGFnZ3JlZ2F0ZWQgcDJnIHNjb3JlcyBmb3IgCmNlbGx0eXBlcy4KCgoKYGBge3J9CmNvcnJlbGF0aW9uc18yNTBrYiA9IGMoKQpmb3IgKGkgaW4gc2VxLmludChkaW0ocDJnX3Njb3JlX2FnZylbMV0pKXsKICByb3dhIDwtIGV4cHJfYWdnW2ksIF0KICByb3dhIDwtIHJvd2EgLSBtZWFuKHJvd2EpCiAgcm93YSA8LSByb3dhIC8gc2Qocm93YSkKICAKICByb3diIDwtIHAyZ19zY29yZV9hZ2dbaSwgXQogIHJvd2IgPC0gcm93YiAtIG1lYW4ocm93YikKICByb3diIDwtIHJvd2IgLyBzZChyb3diKQogIAogIGNvcnJfdmFsdWUgPSBtZWFuKHJvd2EgKiByb3diKQogIGNvcnJlbGF0aW9uc18yNTBrYiA8LSBjKGNvcnJlbGF0aW9uc18yNTBrYiwgY29ycl92YWx1ZSkKICAKfSAKbmFtZXMoY29ycmVsYXRpb25zXzI1MGtiKSA8LSByb3duYW1lcyhwMmdfc2NvcmVfYWdnKQoKcGxvdF8yNTBrYiA8LSBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gY29ycmVsYXRpb25zXzI1MGtiKSwgYmlucyA9IDIwMCwgZmlsbD0iIzY5YjNhMiIpICsKICBsYWJzKHRpdGxlID0gIkdlbmUgYWN0aXZpdHkgc2NvcmVzIGNvbXB1dGVkIGJhc2VkIG9uIHAyZyBsaW5rcyBvbiBlbnRpcmUgY2hyb21vc29tZSIpCnBsb3RfMjUwa2IKYGBgCgoKCiMgS05OIGNlbGwgYWdncmVnYXRlcyBmcm9tIEFyY2hSCgpUbyBjb21wdXRlIHBlYWstdG8tZ2VuZSBsaW5rcywgY2VsbCBhZ2dyZWdhdGVzIGFyZSBjcmVhdGVkIHRvIG92ZXJjb21lIHNwYXJzaXR5IGFzIGRlc2NyaWJlZCBhYm92ZS4gVG8gY3JlYXRlIGNlbGwgYWdncmVnYXRlcywgNTAwIGNlbGxzIGFyZSAKcmFuZG9tbHkgc2FtcGxlZCBmcm9tIGEgbG93LWRpbWVuc2lvbmFsIGVtYmVkZGluZywgZWcuIFBDQSBzcGFjZSBhbmQgdGhlIDUwIG5lYXJlc3QgbmVpZ2hib3JzIG9mIGVhY2ggY2VsbCBhcmUgZGV0ZXJtaW5lZC4gVGhpcyB3YXkgQXJjaFIgY3JlYXRlcyA1MDAgCmFnZ3JlZ2F0ZXMsIGVhY2ggY29uc2lzdGluZyBvZiA1MCBjZWxscy4gQmVsb3csIEkgdXNlZCB0aGVzZSBhZ2dyZWdhdGVzIGZvciBjb21wdXRpbmcgY29ycmVsYXRpb25zIGJldHdlZW4gZGlmZmVyZW50IGdlbmUgYWN0aXZpdHkgc2NvcmVzLCBob3dldmVyIHRoZSAKcmVzdWx0cyBkaWQgbm90IGxvb2sgdmVyeSB1c2FibGUsIHNpbmNlIGEgbG90IG9mIG5lZ2F0aXZlIGNvcnJlbGF0aW9ucyB3ZXJlIG9idGFpbmVkIHRoaXMgd2F5LiBUaGlzIG1pZ2h0IGJlIGR1ZSB0byB0aGVzZXMgYWdncmVnYXRlcyBub3QgYmVpbmcKcmVwcmVzZW50YXRpdmUsIHRvbyBzbWFsbCBvciB0b28gZmV3LiBJIGRlY2lkZWQgdG8gbm90IHVzZSB0aGVzZSBhZ2dyZWFnYXRlcywgYnV0IGluc3RhZWQgdXNlZCBTRUFDZWxscywgd2hpY2ggaXMgYSB0b29sIGZvciBjcmVhdGluZyAKY2VsbCBhZ2dyZWdhdGVzICgibWV0YWNlbGxzIikuIAoKYGBgI3tyfQpybmFfa25uIDwtIHJlYWRSRFMoIjExX2FkZGVkX1JpY2FyZHNfcGVha3MvUGVhazJHZW5lTGlua3Mvc2VSTkEtR3JvdXAtS05OLnJkcyIpCnJuYV9hZ2dfbWF0IDwtIGFzc2F5cyhybmFfa25uKVtbMV1dCnJvd25hbWVzKHJuYV9hZ2dfbWF0KSA8LSByb3dEYXRhKHJuYV9rbm4pJG5hbWUKCmNlbGxfYWdnX2xpc3QgPC0gbWV0YWRhdGEocm5hX2tubilbWzFdXQoKCmtubl9hZ2dyZWdhdGVzIDwtIGZ1bmN0aW9uKG1hdHJpeCwgY2VsbF9hZ2dfbGlzdCl7CiAgIyBlbXB0eSBtYXRyaXggdG8gc3RvcmUgYWdncmVnYXRlcwogIGFnZyA8LSBtYXRyaXgoZGF0YSA9IDAsCiAgICAgICAgICAgICAgICBucm93ID0gZGltKG1hdHJpeClbMV0sCiAgICAgICAgICAgICAgICBuY29sID0gbGVuZ3RoKGNlbGxfYWdnX2xpc3QpLAogICAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KHJvd25hbWVzKG1hdHJpeCksIE5VTEwpKQogIAogIGZvciAoaSBpbiBzZXEuaW50KGxlbmd0aChjZWxsX2FnZ19saXN0KSkpIHsKICAgIGFnZ1ssIGldIDwtIHJvd1N1bXMobWF0cml4WywgY2VsbF9hZ2dfbGlzdFtbaV1dXSkKICB9CiAgcmV0dXJuKGFnZykKfQoKCnJuYV9hZ2cgPC0ga25uX2FnZ3JlZ2F0ZXMoZXhwcl9tYXRfc3ViLCBjZWxsX2FnZ19saXN0KQphZ2dfcDJnX2tubiA8LSBrbm5fYWdncmVnYXRlcyhwMmdfc2NvcmVzLCBjZWxsX2FnZ19saXN0KQoKYXJjaHJfa25uIDwtIGFyY2hyX3Njb3Jlc19tYXRbYXMudmVjdG9yKHJvd25hbWVzKGFnZ19wMmdfa25uKSksXQphZ2dfYXJjaHJfa25uIDwtIGtubl9hZ2dyZWdhdGVzKGFyY2hyX2tubiwgY2VsbF9hZ2dfbGlzdCkKYGBgCgoKYGBgI3tyfQphcmNocl9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX2FyY2hyX2tubiwgIkFyY2hyIGdlbmUgYWN0aXZpdHkgc2NvcmVzIikKcDJnX2tubiA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhybmFfYWdnLCBhZ2dfcDJnX2tubiwgIlBlYWstdG8tZ2VuZSBsaW5rcyBhY3Rpdml0eSBzY29yZXMiKQoKY293cGxvdDo6cGxvdF9ncmlkKGFyY2hyX2tubltbMl1dLCBwMmdfa25uW1syXV0sIG5jb2wgPSAyKQoKZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gcDJnX2tubltbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYXJjaHJfa25uW1sxXV0pLCBhbHBoYSA9IC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHAyZ19rbm5bWzFdXSwgeSA9IGFyY2hyX2tubltbMV1dKSkgKwogIGdlb21fbGluZShhZXMoeCA9IHAyZ19rbm5bWzFdXSwgeSA9IHAyZ19rbm5bWzFdXSksIGNvbCA9ICJyZWQiKQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgCgpgYGAKCiMgRnVuY3Rpb25zCgojIyMgRnVuY3Rpb24gdG8gcHJlcCBwZWFrIGFjY2Vzc2liaWxpdHkgbWF0cml4LCBnZW5lIGV4cHJlc3Npb24gbWF0cml4IGFuZCBwMmctbGluayBtYXRyaXgKCmBgYCN7cn0KcHJlcF9wZWFrX3AyZyA8LSBmdW5jdGlvbihwZWFrX21hdCwgcDJnX21hdCwgaHZnX2xpc3QsIGV4cHJfbWF0KXsKICAjcm93bmFtZXMocGVha19tYXQpIDwtIHNlcS5pbnQoZGltKHBlYWtfbWF0KVsxXSkKICAjY29sbmFtZXMocDJnX21hdCkgPC0gc2VxLmludChkaW0ocDJnX21hdClbMl0pCiAgCiAgIyByZW1vdmUgY29sdW1ucyBvZiBwZWFrcyB3aGljaCBhcmUgbm90IGxpbmtlZCB0byBhbnkgcGVhawogIHAyZ19tYXRfc3ViIDwtIHAyZ19tYXRbLCBjb2xTdW1zKHAyZ19tYXQpICE9IDBdCiAgIyB1c2Ugb25seSBoaWdobHkgdmFyaWFibGUgZ2VuZXMKICBwMmdfbWF0X3N1YiA8LSBwMmdfbWF0X3N1YltodmdfbGlzdCwgXQogICMgcmVtb3ZlIGFueSBnZW5lcyB3aGljaCBhcmUgbm90IGxpbmtlZCB0byBhbnkgcGVhawogIHAyZ19tYXRfc3ViIDwtIHAyZ19tYXRfc3ViW3Jvd1N1bXMocDJnX21hdF9zdWIpICE9IDAsIF0KICBzdG9waWZub3QoYWxsKHJvd25hbWVzKHAyZ19tYXRfc3ViKSAlaW4lIGh2Z19saXN0KSkKICBzdG9waWZub3QoYW55KGlzLm5hKHAyZ19tYXRfc3ViKSA9PSBGQUxTRSkpCiAgCiAgIyBrZWVwIG9ubHkgcGVha3Mgd2hpY2ggYXJlIGxpbmtlZCB0byBnZW5lcyBpbiB0aGUgYWNjZXNzaWJpbGl0eSBtYXRyaXgKICBwZWFrX21hdF9zdWIgPC0gcGVha19tYXRbY29sbmFtZXMocDJnX21hdF9zdWIpLCBdCiAgc3RvcGlmbm90KHJvd25hbWVzKHBlYWtfbWF0X3N1YikgPT0gY29sbmFtZXMocDJnX21hdF9zdWIpKQogIHN0b3BpZm5vdChhbnkoaXMubmEocGVha19tYXRfc3ViKSA9PSBGQUxTRSkpCiAgc3RvcGlmbm90KGRpbShwZWFrX21hdF9zdWIpWzFdID09IGRpbShwMmdfbWF0X3N1YilbMl0pCiAgCiAgZXhwcl9tYXRfc3ViIDwtIGV4cHJfbWF0W2FzLnZlY3Rvcihyb3duYW1lcyhwMmdfbWF0X3N1YikpLCBdCiAgc3RvcGlmbm90KHJvd25hbWVzKGV4cHJfbWF0X3N1YikgPT0gcm93bmFtZXMocDJnX21hdF9zdWIpKQogIHJldHVybihsaXN0KHBlYWtfbWF0X3N1YiwgcDJnX21hdF9zdWIsIGV4cHJfbWF0X3N1YikpCn0KYGBgCgoKCgojIyMgRnVuY3Rpb24gdG8gY3JlYXRlIGFnZ3JlZ2F0ZSBtYXRyaWNlczoKCmBgYHtyfQojIHRoZSBkYXRhIG1hdHJpeCBuZWVkcyB0byBiZSBvZiBkaW1lbnNpb24gZmVhdHVyZXMgeCBjZWxscwojIHRoZSBjb2x1bW4gb2YgdGhlIGNvbERhdGEgb2YgdGhlIHNjZSBvYmplY3Qgd2hlcmUgY2VsbHR5cGVzIGFyZSBzdG9yZWQKIyBuZWVkcyB0byBiZSBjYWxsZWQgImNlbGx0eXBlcyIKY3JlYXRlX2NlbGx0eXBlX2FnZ3JlZ2F0ZXMgPC0gZnVuY3Rpb24oc2NlLCBkYXRhX21hdHJpeCwgY2VsbHR5cGVzKSB7CiAgI2NyZWF0ZSBlbXB0eSBtYXRyaXggdG8gc3RvcmUgYWdncmVnYXRlcwogIGFnZyA8LSBtYXRyaXgoZGF0YSA9IDAsCiAgICAgICAgICAgICAgICBucm93ID0gbnJvdyhkYXRhX21hdHJpeCksCiAgICAgICAgICAgICAgICBuY29sID0gbGVuZ3RoKGNlbGx0eXBlcyksCiAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoZGF0YV9tYXRyaXgpLCBjZWxsdHlwZXMpKQogIAoKICBmb3IgKGNlbGx0eXBlIGluIGNlbGx0eXBlcykgewogICAgYmFyY29kZXMgPC0gcm93bmFtZXMoY29sRGF0YShzY2UpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihjZWxsdHlwZXMgPT0gY2VsbHR5cGUpKQogICAgYWdnWywgY2VsbHR5cGVdIDwtIHJvd1N1bXMoZGF0YV9tYXRyaXhbLCBiYXJjb2Rlc10pCiAgfQogIHJldHVybihhZ2cpCn0KCgpjcmVhdGVfY2VsbHR5cGVfYWdncmVnYXRlc19wMmdfc2NvcmVzIDwtIGZ1bmN0aW9uKGdlbmVfZXhwcl9zY2UsIHAyZ19zY29yZV9tYXRyaXgsIGNlbGx0eXBlcykgewogICAgI2NyZWF0ZSBlbXB0eSBtYXRyaXggdG8gc3RvcmUgYWdncmVnYXRlcwogIGFnZyA8LSBtYXRyaXgoZGF0YSA9IDAsCiAgICAgICAgICAgICAgICBucm93ID0gbnJvdyhwMmdfc2NvcmVfbWF0cml4KSwKICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgoY2VsbHR5cGVzKSwKICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhwMmdfc2NvcmVfbWF0cml4KSwgY2VsbHR5cGVzKSkKICAKCiAgZm9yIChjZWxsdHlwZSBpbiBjZWxsdHlwZXMpIHsKICAgIGJhcmNvZGVzIDwtIHJvd25hbWVzKGNvbERhdGEoZ2VuZV9leHByX3NjZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNlbGx0eXBlcyA9PSBjZWxsdHlwZSkpCiAgICBhZ2dbLCBjZWxsdHlwZV0gPC0gcm93U3VtcyhwMmdfc2NvcmVfbWF0cml4WywgYmFyY29kZXNdKQogIH0KICByZXR1cm4oYWdnKQp9CgoKY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyA8LSBmdW5jdGlvbihkYXRhX21hdHJpeCwgc2VhY2VsbHNfZGYpewogIGFnZyA8LSBtYXRyaXgoZGF0YSA9IDAsCiAgICAgICAgICAgICAgICBucm93ID0gbnJvdyhkYXRhX21hdHJpeCksCiAgICAgICAgICAgICAgICBuY29sID0gbGVuZ3RoKHVuaXF1ZShzZWFjZWxsc19kZiRTRUFDZWxsKSksCiAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoZGF0YV9tYXRyaXgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUoc2VhY2VsbHNfZGYkU0VBQ2VsbCkpKQogICNzdG9waWZub3QobnJvdyhhZ2cpID09IG5yb3coZGF0YV9tYXRyaXgpKQogIGZvciAoc2VhY2VsbCBpbiB1bmlxdWUoc2VhY2VsbHNfZGYkU0VBQ2VsbCkpewogICAgI3ByaW50KHNlYWNlbGwpCiAgICBiYXJjb2RlcyA8LSAoc2VhY2VsbHNfZGYgJT4lIGZpbHRlcihTRUFDZWxsID09IHNlYWNlbGwpKSRpbmRleAogICAgI3ByaW50KGJhcmNvZGVzKQogICAgaWYgKGxlbmd0aChiYXJjb2RlcykgPT0gMSl7CiAgICAgIGFnZ1ssIHNlYWNlbGxdIDwtIGRhdGFfbWF0cml4WywgYmFyY29kZXNdCiAgICB9IGVsc2V7CiAgICAgIGFnZ1ssIHNlYWNlbGxdIDwtIHJvd1N1bXMoZGF0YV9tYXRyaXhbLCBiYXJjb2Rlc10pCiAgICB9CiAgfQogIHJldHVybihhZ2cpCn0KCmBgYAoKCiMjIyBGdW5jdGlvbiB0byBjb21wdXRlIHJvdy13aXNlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHR3byBtYXRyaWNlczoKCmBgYHtyfQpyb3d3aXNlX2NvcnJlbGF0aW9ucyA8LSBmdW5jdGlvbihNYXRyaXhBLCBNYXRyaXhCLCBuYW1lKSB7CiAgaW50ZXJzZWN0X2dlbmVzIDwtIGludGVyc2VjdChyb3duYW1lcyhNYXRyaXhBKSwgcm93bmFtZXMoTWF0cml4QikpCiAgTWF0cml4QSA8LSBNYXRyaXhBW2ludGVyc2VjdF9nZW5lcywgXQogIE1hdHJpeEIgPC0gTWF0cml4QltpbnRlcnNlY3RfZ2VuZXMsIF0KICBjb3JyZWxhdGlvbnMgPC0gYygpCiAgZm9yIChpIGluIHNlcS5pbnQoZGltKE1hdHJpeEEpWzFdKSkgewogICAgcm93QSA8LSBNYXRyaXhBW2ksIF0KICAgIHJvd0EgPC0gcm93QSAtIG1lYW4ocm93QSkKICAgIGlmIChzZChyb3dBKSAhPSAwKSB7CiAgICAgIHJvd0EgPC0gcm93QSAvIHNkKHJvd0EpCiAgICB9CiAgCiAgICByb3dCIDwtIE1hdHJpeEJbaSwgXQogICAgcm93QiA8LSByb3dCIC0gbWVhbihyb3dCKQogICAgaWYgKHNkKHJvd0IpICE9IDApewogICAgICByb3dCIDwtIHJvd0IgLyBzZChyb3dCKQogICAgfQogICAgCiAgICBjb3JyX3ZhbHVlIDwtIG1lYW4ocm93QSAqIHJvd0IpCiAgICBjb3JyZWxhdGlvbnMgPC0gYyhjb3JyZWxhdGlvbnMsIGNvcnJfdmFsdWUpCiAgfQogIG5hbWVzKGNvcnJlbGF0aW9ucykgPC0gcm93bmFtZXMoTWF0cml4QSkKICBwbG90IDwtIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBjb3JyZWxhdGlvbnMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlucyA9IDIwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGw9IiM2OWIzYTIiKSArIGxhYnModGl0bGUgPSBwYXN0ZTAobmFtZSkpCiAgcmV0dXJuKGxpc3QoY29ycmVsYXRpb25zLCBwbG90KSkKfQpgYGAKCgojIyMgRnVuY3Rpb24gZm9yIEFyY2hSIEtOTiBhZ2dyZWdhdGVzCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBjb21wdXRlIGFnZ3JlZ2F0ZXMgd2l0aCBrbm4gZnJvbSBBcmNoUgprbm5fYWdncmVnYXRlcyA8LSBmdW5jdGlvbihtYXRyaXgsIGNlbGxfYWdnX2xpc3QpewogICMgZW1wdHkgbWF0cml4IHRvIHN0b3JlIGFnZ3JlZ2F0ZXMKICBhZ2cgPC0gbWF0cml4KGRhdGEgPSAwLAogICAgICAgICAgICAgICAgbnJvdyA9IGRpbShtYXRyaXgpWzFdLAogICAgICAgICAgICAgICAgbmNvbCA9IGxlbmd0aChjZWxsX2FnZ19saXN0KSwKICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhtYXRyaXgpLCBOVUxMKSkKICAKICBmb3IgKGkgaW4gc2VxLmludChsZW5ndGgoY2VsbF9hZ2dfbGlzdCkpKSB7CiAgICBhZ2dbLCBpXSA8LSByb3dTdW1zKG1hdHJpeFssIGNlbGxfYWdnX2xpc3RbW2ldXV0pCiAgfQogIHJldHVybihhZ2cpCn0KCmBgYAoKIyBDZWxsdHlwZSBhZ2dyZWdhdGVzCgojIyBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcwoKVG8gY29tcHV0ZSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBBcmNoUiBnZW5lIGFjdGl2aXR5IApzY29yZXMgSSBmaXJzdCBhZ2dyZWdhdGVkIGNlbGxzIGFjY29yZGluZyB0byBjZWxsdHlwZXMgdG8gY29tcHV0ZSAKY29ycmVsYXRpb25zLiBBcyBjYW4gYmUgc2VlbiBpbiB0aGUgcGxvdCBiZWxvdywgdGhpcyB5aWVsZHMgdmVyeSBoaWdoIApjb3JyZWxhdGlvbiB2YWx1ZXMuIFRoaXMgaXMgYXMgZXhwZWN0ZWQsIHNpbmNlIGluIFtAR3JhbmphXSB0aGUgYXV0aG9ycyAKY29tcGFyZWQgNTIgZGlmZmVyZW50IHdheXMgb2YgY29tcHV0aW5nIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGZyb20gQVRBQy1zZXEgCmRhdGEgYW5kIGZvdW5kIHRoZWlyIG1ldGhvZCB0byBiZSB0aGUgYmVzdCBvbmUuIAoKCmBgYHtyLCBmaWcud2lkdGg9OH0KYXJjaHJfc2NvcmVzX3N1YiA8LSBhcmNocl9zY29yZXNfbWF0W2FzLnZlY3Rvcihyb3duYW1lcyhleHByX21hdF9zdWIpKSwgXQoKbmFtZSA8LSAiQXJjaFJfc2NvcmVzLCBDZWxsdHlwZSBhZ2dyZWdhdGVzIgoKYXJjaHJfc2NvcmVzX2FnZyA8LSBjcmVhdGVfY2VsbHR5cGVfYWdncmVnYXRlcyhhcmNocl9zY29yZXMsIGFyY2hyX3Njb3Jlc19zdWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShjb2xEYXRhKGFyY2hyX3Njb3JlcykkY2VsbHR5cGVzKSkKc3RvcGlmbm90KGFueShpcy5uYShhcmNocl9zY29yZXNfYWdnKSkgPT0gRkFMU0UpCgpjb3JycyA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhleHByX2FnZywgYXJjaHJfc2NvcmVzX2FnZywgbmFtZSkKYXJjaHJfY29yciA8LSBjb3Jyc1sxXQpjb3dwbG90OjpwbG90X2dyaWQocGxvdF8yNTBrYiArIGxhYnModGl0bGUgPSAiUDJnLWxpbmtzIGFjdGl2aXR5IHNjb3JlcywgQ2VsbHR5cGUgYWdncmVnYXRlcyIpLCBjb3Jyc1tbMl1dLCBuY29sID0gMikKYGBgCgoKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD04fQojLCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0PTV9CmdncGxvdCgpICsgI2dlb21fZGVuc2l0eTJkX2ZpbGxlZChhZXMoeCA9IGNvcnJlbGF0aW9uc18yNTBrYiwgeSA9IGNvcnJzWzFdKSkgIysKICBnZW9tX3BvaW50KGFlcyh4ID0gY29ycmVsYXRpb25zXzI1MGtiLCB5ID0gY29ycnNbWzFdXSkpICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gY29ycmVsYXRpb25zXzI1MGtiLCB5ID0gY29ycnNbWzFdXSksIGFscGhhID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gIGNvcnJzW1sxXV0sICBjb3Jyc1tbMV1dKSwgY29sb3IgPSAicmVkIikgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gYW5kIHAyZyBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgeSA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gYW5kIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgIHRpdGxlID0gIkNlbGx0eXBlIGFnZ3JlZ2F0ZXMiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKQoKCiMgZ2dwbG90KCkgKyBnZW9tX3BvaW50KGFlcyh4ID0gYXJjaHJfc2NvcmVzX3N1YlsiSGJhLWExIixdLCB5ID0gcDJnX3Njb3Jlc1siSGJhLWExIixdKSkKIyBnZ3Bsb3QoKSArIGdlb21fcG9pbnQoYWVzKHggPSBhcmNocl9zY29yZXNfc3ViWyJHYXRhNiIsXSwgeSA9IHAyZ19zY29yZXNbIkhiYS1hMSIsXSkpCgpgYGAKCiMgU0VBQ2VsbCBhZ2dyZWdhdGVzCgpJbnN0ZWFkIG9mIHVzaW5nIGNlbGx0eXBlIGFnZ3JlZ2F0ZXMgYXMgYWJvdmUsIGFub3RoZXIgb3B0aW9uIGlzIHRvCnVzZSBTRUFDZWxscyBhcyBkZXNjcmliZWQgaW4gW0BQZXJzYWQyMDIyXS4gVGhlc2Ugd2VyZSBjb21wdXRlZCB1c2luZwpQeXRob24gYW5kIHRoZSByZXN1bHRpbmcgY2VsbCBhZ2dyZWdhdGVzICgibWV0YWNlbGxzIikgYXJlIHVzZWQgZm9yCmFnZ3JlZ2F0aW5nIGdlbmUgZXhwcmVzc2lvbiBhbmQgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYmVsb3cuIFRoZSBjb3JyZWxhdGlvbnMKd2hlbiB1c2luZyBTRUFDZWxscyBhcmUgbXVjaCBoaWdoZXIgdGhhbiB0aGUgY29ycmVsYXRpb25zIG9idGFpbmVkIHVzaW5nIAp0aGUgQXJjaFIgY2VsbCBhZ2dyZWdhdGVzLiBGb3IgdGhpcyByZWFzb24gSSB3aWxsIHVzZSBTRUFDZWxscyBmb3IgY29tcHV0aW5nCmNvcnJlbGF0aW9ucyBpbiB0aGUgZm9sbG93aW5nIHN0ZXBzLiAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0PTV9CgoKc2VhY2VsbHMgPC0gc2VhY2VsbHMgJT4lIGZpbHRlcihpbmRleCAlaW4lIGNvbG5hbWVzKGV4cHJfbWF0KSkKCnN0b3BpZm5vdChucm93KHAyZ19zY29yZXMpID09IG5yb3coZXhwcl9tYXRfc3ViKSkKCnNlYWNlbGxfcDJnX2FnZyA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKHAyZ19zY29yZXMsIHNlYWNlbGxzKQpzZWFjZWxsX3JuYV9hZ2cgIDwtIGNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMoZXhwcl9tYXRfc3ViLCBzZWFjZWxscykKc2VhY2VsbF9hcmNocl9hZ2cgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhhcmNocl9zY29yZXNfc3ViLCBzZWFjZWxscykKCgpzZWFjZWxsX2NvcnJfcDJnIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHNlYWNlbGxfcm5hX2FnZyAsIHNlYWNlbGxfcDJnX2FnZywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlAyZyBsaW5rcyBvZiBlbnRpcmUgY2hyb21vc29tZSwgU0VBY2VsbHMiICkKCnNlYWNlbGxfY29ycl9hcmNociA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhzZWFjZWxsX3JuYV9hZ2csIHNlYWNlbGxfYXJjaHJfYWdnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcywgU0VBY2VsbHMiKQoKY293cGxvdDo6cGxvdF9ncmlkKHNlYWNlbGxfY29ycl9wMmdbWzJdXSwgc2VhY2VsbF9jb3JyX2FyY2hyW1syXV0sIG5jb2wgPSAyKQoKCmdncGxvdCgpICsgI2dlb21fZGVuc2l0eTJkX2ZpbGxlZChhZXMoeCA9IGNvcnJlbGF0aW9uc18yNTBrYiwgeSA9IGNvcnJzWzFdKSkgIysKICBnZW9tX3BvaW50KGFlcyh4ID0gc2VhY2VsbF9jb3JyX3AyZ1tbMV1dLCB5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV0pKSArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IHNlYWNlbGxfY29ycl9wMmdbWzFdXSwgeSA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXSwgeSA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dKSwgY29sb3IgPSAicmVkIiApICArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiBhbmQgcDJnIGFjdGl2aXR5IHNjb3JlcyIsCiAgICAgICB5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiBhbmQgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgdGl0bGUgPSAiU0VBQ2VsbHMiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKQoKYGBgCgoKCgojIERpc3RhbmNlIHdlaWdodHMKClVzaW5nIEFyY2hSIFtAR3JhbmphXSBJIGNvbXB1dGVkIHBlYWstdG8tZ2VuZSBsaW5rcyBhY3Jvc3MgdGhlIGVudGlyZSAKY2hyb21vc29tZSwgYnV0IG5vdCBiZXR3ZWVuIGNocm9tc29tZXMuIFRoaXMgbWVhbnMgdGhhdCBhIGxvdCBvZiAKY29ycmVsYXRpb25zIGFyZSBmb3VuZCBiZXR3ZWVuIHBlYWtzIHZlcnkgZmFyIGF3YXkgZnJvbSB0aGUgcHJvbW90ZXIvZ2VuZQp0aGV5IGFyZSBsaW5rZWQgdG8uIEV2ZW4gdGhvdWdoIHRoZXNlIGNvcnJlbGF0aW9ucyBjYW4gYmUgcXVpdGUgaGlnaCBhbmQgaW50ZXJhY3Rpb25zCmJldHdlZW4gZW5oYW5jZXJzIGFuZCBwcm9tb3RlcnMgY2FuIG9jY3VyIG92ZXIgbWVnYWJhc2UgZGlzdGFuY2VzLCBhIHJlYWwKYmlvbG9naWNhbCBpbnRlcmFjdGlvbiBiZWNvbWVzIGxlc3MgbGlrZWx5IHRoZSBsYXJnZXIgdGhlIGRpc3RhbmNlIGlzLiBUaGVyZWZvcmUsIHNpbmNlIHdlciBhcmUgaW50ZXJlc3RlZCBpbiBiaW9sb2dpY2FsbHkgcmVsZXZhbnQgYW5kIG5vdApzcHVyaW91cyBjb3JyZWxhdGlvbnMuIFRoZXJlZm9yZSwgYXMgc3VnZ2VzdGVkIGJ5IFtAR3JhbmphXSwgSSBhZGRlZCAKZGlzdGFuY2Ugd2VpZ2h0cywgc3VjaCB0aGF0IGZhcnRoZXIgYXdheSBwZWFrcyBsaW5rZWQgdG8gYSBnZW5lIGNvbnRyaWJ1dGUKbGVzcyB0byB0aGUgZ2VuZSBhY3Rpdml0eSBzY29yZSBvZiB0aGlzIHBhcnRpY3VsYXIgZ2VuZS4gCgpIZXJlLCBJIHVzZWQgYSBkaXN0YW5jZSBkZWNheSBmcm9tIHRoZSBUU1MsIGNvbXB1dGVkIGFzIGZvbGxvd3M6Cgokd2VpZ2h0ID0gZV57LShhYnMoZGlzdFRTUy9jKSl9JCB3aXRoICRjJCBiZWluZyBhIGNvbnN0YW50IGRldGVybWluaW5nIHRoZSBleHBvbmVudGlhbApkZWNheSByYXRlIG9mIHRoZSBkaXN0YW5jZSB3ZWlnaHRzLiBCZWxvdyBJIHRyaWVkIGRpZmZlcmVudCByYXRlcyB0byBiZXR0ZXIgdW5kZXJzdGFuZCAKd2hldGhlciB3ZSBjYW4gaW1wcm92ZSB0aGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYnkgZ2l2aW5nIGEgaGlnaGVyIHdlaWdodCB0bwpjbG9zZSBwZWFrcyB0aGFuIHRvIGZhciBhd2F5IHBlYWtzLiBBcyBjYW4gYmUgc2VlbiBiZWxvdyB0aGlzIGRpZCBub3QgaW1wcm92ZSwgdGhlCnNjb3JlcywgYnV0IHJhdGhlciB0aGUgc2NvcmVzIGJlY2FtZSB3b3JzZSwgd2hpY2ggaXMgcHJvYmFibHkgZHVlIHRvIHRoZSBmYWN0IHRoYXQKbW9zdCBjb3JyZWxhdGlvbiB2YWx1ZXMgd2lsbCBnZXQgdmVyeSBzbWFsbCB3ZWlnaHRzIHRoaXMgd2F5IGFuZCBtb3N0IHBlYWtzIGxpbmtlZAp3aXRoIGEgZ2VuZSwgZXZlbiBpZiB0aGUgY29ycmVsYXRpb24gdmFsdWUgaXMgaGlnaCwgd2lsbCBub3QgY29udHJpYnV0ZSB0byB0aGUgZ2VuZQphY3Rpdml0eSBzY29yZSBhbnltb3JlLgoKKipDYXJlZnVsOiBUaGUgcDJnIGlua3MgaW4gQXJjaFIgYXJlIGNvbXB1dGVkIGZvciBwZWFrIGFuZCBnZW5lIHBhaXJzIHdoaWNoIGFyZSAKd2l0aGluIGEgY2VydGFpbiBkaXN0YW5jZSBmcm9tIGVhY2ggb3RoZXIuIEhvd2V2ZXIsIG5vdCB0aGUgcmVhbCBUU1Mgb2YgYSBnZW5lIGlzCnVzZWQgZm9yIHRoaXMsIGJ1dCByYXRlciB0aGUgZGlzdGFuY2UgYmV0d2VlbiBzdGFydCBjb29yZGluYXRlCm9mIGEgZ2VuZSBhbmQgcGVhayBzdGFydCBjb29yZGluYXRlLCBub3QgdGFraW5nIGludG8gY29uc2lkZXJhdGlvbiB0aGUgc3RyYW5kIGRpcmVjdGlvbmFsaXR5LgoKCiEhISEhISBDaGVjayBhZ2FpbiEgQmVjYXVzZSBoZXJlIHNvbWV0aGluZyBpcyB3cm9uZyB3aXRoIHRoZSB3YXkgSSBjb21wdXRlIHRoZSBkaXN0YW5jZSB3ZWlnaHRzISBTb21ldGltZXMgSSBuZWVkIHRvIHVzZSB0aGUgc3RhcnQgY29vcmRpbmF0ZSBpbnN0ZWFkIG9mIHRoZSBlbmQgY29vcmRpbmF0ZS4gVHJ5IGFsd2F5cyB1c2luZyB0aGUgZ2VuZSBzdGFydCBjb29yZGluYXRlIGluc3RlYWQgb2Ygc3dhcHBpbmcgc3RhcnQKYW5kIGVuZCBjb29yZGluYXRlcyBpbiB0aGUgZGF0YWZyYW1lLiBNYXliZSB0aGlzIGlzIGRvbmUgYXV0b21hdGljYWxsIHdoZW4gY29udmVydGVkIAp0byBkYXRhZnJhbWU/CgojIyMgRnVuY3Rpb24gdG8gY29tcHV0ZSBkaXN0YW5jZS13ZWlnaHRlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmcm9tIHAyZyBsaW5rcwoKYGBge3J9CiMgQXMgaW5wdXQgZm9yIHRoaXMgZnVuY3Rpb24gaXQgaXMgYmVzdCB0byB1c2Ugb25seSB0aGUgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKZGlzdGFuY193ZWlnaHRlZF9nZW5lX2FjdGl2aXR5X3Njb3JlcyA8LSBmdW5jdGlvbihwMmdfbWF0X3N1YiwgZ2VuZU1vZGVsID0gImV4cCgtZGlzdGFuY2UvNTAwMCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSA1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCwgbGlua3MsIHAyZ19vcmlnaW5hbCwgZ2VuZV9leHByKXsKICBhdGFjX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMV1dCiAgI3JuYV9ncmFuZ2VzIDwtIG1ldGFkYXRhKHAyZ19vcmlnaW5hbClbWzJdXQogIGdlbmVfYW5ubyA8LSByb3dEYXRhKGdlbmVfZXhwcikKICAKICAjIGNyZWF0ZSBnZW5lIGFubm90YXRpb25zIHdpdGggc3RhcnQgY29vcmRpbmF0ZSBvZiBlYWNoIGdlbmUKICAjIHN1YnNldCB0byBjb250YWluIG9ubHkgZ2VuZXMgd2hpY2ggYXJlIGluY2x1ZGVkIGluIG91ciBwZWFrMmdlbmUgbWF0cml4CiAgZ2VuZV9hbm5vIDwtIGdlbmVfYW5ubyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogICAgZmlsdGVyKG5hbWUgJWluJSByb3duYW1lcyhwMmdfbWF0X3N1YikpICU+JQogICAgbXV0YXRlKHN0cmFuZCA9IGlmZWxzZShzdHJhbmQgPT0gMSwgIisiLCAiLSIpKSAlPiUgCiAgICBtdXRhdGUoc3RhcnRfY29vcmQgPSBpZmVsc2Uoc3RyYW5kID09ICIrIiwgc3RhcnQsIGVuZCkpICU+JSAKICAgIHJlbmFtZShnZW5lID0gbmFtZSkgIyU+JSBHUmFuZ2VzKCkKCiAgIyBzdWJzZXQgYXRhYyBncmFuZ2VzICYgZ2V0IG1pZGRsZSBvZiBlYWNoIHBlYWsKICBwb3NfYXRhY19ncmFuZ2VzIDwtIGF0YWNfZ3JhbmdlcyAgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeEFUQUMgPSBzZXEobnJvdyguKSkpICU+JSAKICAgICMgZ3JvdXBfYnkoc2VxbmFtZXMpICU+JQogICAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICAgIyB1bmdyb3VwICU+JQogICAgI3RpZHlyOjp1bml0ZShjaHJfaWR4LCBzZXFuYW1lcywgaWR4LCByZW1vdmUgPSBGQUxTRSwgc2VwID0gIl8iKSAlPiUgCiAgICBmaWx0ZXIoaWR4QVRBQyAlaW4lIGNvbG5hbWVzKHAyZ19tYXRfc3ViKSkgJT4lIAogICAgbXV0YXRlKG1pZGRsZSA9IHN0YXJ0ICsgMzAwKSAjJT4lIEdSYW5nZXMoKSAKICAKICAjVE9ETzogRmlsdGVyIGZvciBnZW5lcyEKICBzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhBVEFDKSkgPT0gZGltKHBvc19hdGFjX2dyYW5nZXMpW1sxXV0pCiAgc3RvcGlmbm90KGxlbmd0aCh1bmlxdWUobGlua3MkaWR4Uk5BKSkgPT0gZGltKGdlbmVfYW5ubylbWzFdXSkKICAjcDJnX2ZpbHQgPC0gcDJnX29yaWdpbmFsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGZpbHRlcihnZW5lICVpbiUgcm93bmFtZXMocDJnX21hdCkpCiAgCiAgCiAgIyBjb21iaW5lIHRoZSB0aHJlZSBkYXRhZnJhbWVzCiAgcDJnX2pvaW4gPC0gbGVmdF9qb2luKGxpbmtzLCBhcy5kYXRhLmZyYW1lKHBvc19hdGFjX2dyYW5nZXMpLAogICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhBVEFDIikKICBwMmdfam9pbiA8LSBsZWZ0X2pvaW4ocDJnX2pvaW4sIGFzLmRhdGEuZnJhbWUoZ2VuZV9hbm5vKSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4Uk5BIiwgc3VmZml4ID0gYygiLmF0YWMiLCAiLnJuYSIpKQoKICAjIGNvbXB1dGUgZGlzdGFuY2UgYW5kIGRpc3RhbmNlIHdlaWdodHMgCiAgcDJnX2pvaW4gPC0gcDJnX2pvaW4gJT4lIAogICAgbXV0YXRlKGRpc3RhbmNlID0gYWJzKHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKSkgJT4lCiAgICBtdXRhdGUoZGlzdGFuY2Vfd2VpZ2h0ID0gZXZhbChwYXJzZSh0ZXh0PWdlbmVNb2RlbCkpKQogIAogIAogICMgY3JlYXRlIGRpc3RhbmNlIHdlaWdodCBtYXRyaXgKICBwMmdfZHcgPC0gc3BhcnNlTWF0cml4KGkgPSBwMmdfam9pbiRpZHhSTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICBqID0gcDJnX2pvaW4kaWR4QVRBQywKICAgICAgICAgICAgICAgICAgICAgICAgIHggPSBwMmdfam9pbiRkaXN0YW5jZV93ZWlnaHQsCiAgICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gYyhkaW0oYXNzYXlzKGdlbmVfZXhwcilbWzFdXSlbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW0ocGVha19tYXQpWzFdKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChyb3dEYXRhKGdlbmVfZXhwcikkbmFtZSAsIAogICAgICAgICAgICAgICAgICAgICAgICAgc2VxLmludChkaW0ocGVha19tYXQpWzFdKSkpCgoKICBwMmdfZHcgPC0gcDJnX2R3W2FzLnZlY3Rvcihyb3duYW1lcyhwMmdfbWF0X3N1YikpLCBjb2xuYW1lcyhwMmdfbWF0X3N1YildCiAgCiAgIyBlbGVtZW50d2lzZSBtYXRyaXggbXVsdGlwbGljYXRpb24KICB3ZWlnaHRlZF9wMmdfbWF0IDwtIHAyZ19tYXRfc3ViICogcDJnX2R3CiAgCiAgcHJpbnQocGFzdGUobGVuZ3RoKHdoaWNoKHJvd1N1bXMod2VpZ2h0ZWRfcDJnX21hdCkgPT0gMCkpLCAiZ2VuZXMgaGF2ZSBvbmx5IHplcm8gY29ycmVsYXRpb24gdmFsdWVzLCBzbyB3ZSB3aWxsIHJlbW92ZSB0aGVtLiIpKQogIHdlaWdodGVkX3AyZ19tYXQgPC0gd2VpZ2h0ZWRfcDJnX21hdFtyb3dTdW1zKHdlaWdodGVkX3AyZ19tYXQpICE9IDAsIF0KICBwcmludChwYXN0ZTAoIldlIGFyZSBsZWZ0IHdpdGggIiwgZGltKHdlaWdodGVkX3AyZ19tYXQpWzFdLCAiIGdlbmVzIikpCiAgCiAgIyBjb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGJhc2VkIG9uIGRpc3RhbmNlLXdlaWdodGVkIHBlYWsyZ2VuZSBtYXRyaXgKICB3ZWlnaHRlZF9zY29yZXMgPC0gZ2VuZV9hY3Rpdml0eV9zY29yZXMocGVha19tYXRfc3ViLCB3ZWlnaHRlZF9wMmdfbWF0KQogIAogIHJldHVybih3ZWlnaHRlZF9zY29yZXMpIAp9CmBgYAoKYGBgI3tyfQp3ZWlnaHRlZF9zY29yZXMgPC0gZGlzdGFuY193ZWlnaHRlZF9nZW5lX2FjdGl2aXR5X3Njb3JlcyhwMmdfbWF0X3N1YiwgZ2VuZU1vZGVsID0gImV4cCgtZGlzdGFuY2UvNTAwMCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSA1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCwgbGlua3MsIHAyZywgZ2VuZV9leHByKQpgYGAKIyMgS05OIGFnZ3JlZ2F0ZXMKCgpgYGB7cn0Kcm0obWV0YV9ybmEpCiNybShwMmdfbWF0KQpnYyhyZXNldCA9IFRSVUUpCgptb2RlbF9saXN0IDwtIGMoImV4cCgtYWJzKGRpc3RhbmNlKS81MDAwKSIsICJleHAoLWFicyhkaXN0YW5jZSkvNTAwMDApIiwKICAgICAgICAgICAgICAgICJleHAoLWFicyhkaXN0YW5jZSkvNTAwMDAwKSIsICJleHAoLWFicyhkaXN0YW5jZSkvNTAwMDAwMCkiKQoKIyByZWFkIGluIGtubgpybmFfa25uIDwtIHJlYWRSRFMoIjExX2FkZGVkX1JpY2FyZHNfcGVha3NfcDJnX2VudGlyZV9jaHJvbW9zb21lL1BlYWsyR2VuZUxpbmtzL3NlUk5BLUdyb3VwLUtOTi5yZHMiKQpjZWxsX2FnZ19saXN0IDwtIG1ldGFkYXRhKHJuYV9rbm4pW1sxXV0KCgoKIyBhZ2dyZWdhdGUgZm9yIGdlbmUgZXhwcmVzc2lvbiwgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYW5kIHNpbXBsZSBwMmcgbGlua3MKcm5hX2FnZyA8LSBrbm5fYWdncmVnYXRlcyhleHByX21hdF9zdWIsIGNlbGxfYWdnX2xpc3QpCmFyY2hyX2tubiA8LSBhcmNocl9zY29yZXNfbWF0W2FzLnZlY3Rvcihyb3duYW1lcyhybmFfYWdnKSksXQphZ2dfYXJjaHJfa25uIDwtIGtubl9hZ2dyZWdhdGVzKGFyY2hyX2tubiwgY2VsbF9hZ2dfbGlzdCkKYWdnX3AyZ19rbm4gPC0ga25uX2FnZ3JlZ2F0ZXMocDJnX3Njb3JlcywgY2VsbF9hZ2dfbGlzdCkKCiMgY29tcHV0ZSByb3d3aXNlIGNvcnJlbGF0aW9ucwphcmNocl9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX2FyY2hyX2tubiwgIkFyY2hyIGdlbmUgYWN0aXZpdHkgc2NvcmVzLCBLTk4gYWdncmVnYXRlcyIpCnAyZ19rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX3AyZ19rbm4sICJQZWFrLXRvLWdlbmUgbGlua3MgYWN0aXZpdHkgc2NvcmVzLCBLTk4gYWdncmVnYXRlcyIpCmNvd3Bsb3Q6OnBsb3RfZ3JpZChhcmNocl9rbm5bWzJdXSwgcDJnX2tubltbMl1dLCBuY29sID0gMikKCgojIHByZXBhcmUgbGlzdHMgdG8gc3RvcmUgY29ycmVsYXRpb24gdmVjdG9ycyBhbmQgY29ycmVsYXRpb24gaGlzdG9ncmFtcwpjb3JyX2xpc3QgPC0gbGlzdChhcmNocl9rbm5bWzFdXSwgcDJnX2tubltbMV1dKQoKIyBjb21wdXRlIHRoZSBkaXN0YW5jZS13ZWlnaHRlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmcm9tIHAyZyBsaW5rcyB1c2luZyBkaWZmZXJlbnQgCiMgZGlzdGFuY2Ugd2VpZ2h0IG1vZGVscwpmb3IgKG1vZGVsIGluIG1vZGVsX2xpc3QpewogIHdlaWdodGVkX3Njb3JlcyA8LSBkaXN0YW5jX3dlaWdodGVkX2dlbmVfYWN0aXZpdHlfc2NvcmVzKHAyZ19tYXRfc3ViLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lTW9kZWwgPSBtb2RlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gNTAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVha19tYXQgPSBwZWFrX21hdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5rcyA9IGxpbmtzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMmdfb3JpZ2luYWwgPSBwMmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfZXhwciA9IGdlbmVfZXhwcikKICBhZ2dfZGlzdCA8LSBrbm5fYWdncmVnYXRlcyh3ZWlnaHRlZF9zY29yZXMsIGNlbGxfYWdnX2xpc3QpCiAgZGlzdF9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX2Rpc3QsIG5hbWUgPSBwYXN0ZTAoIlAyZyBhY3Rpdml0eSBzY29yZXMsIGRpc3RhbmNlIHdlaWh0ZWQsIG1vZGVsID0gIiwgbW9kZWwpKQogIHN0b3BpZm5vdChhbnkoaXMubmEoZGlzdF9rbm4pKSA9PSBGQUxTRSkKICAKICBjb3JyX2xpc3QgPC0gYXBwZW5kKGNvcnJfbGlzdCwgZGlzdF9rbm5bWzFdXSkKICBwcmludChkaXN0X2tubltbMl1dKQogICNjb3JyX3Bsb3RzX2xpc3QgPC0gYXBwZW5kKGNvcnJfcGxvdHNfbGlzdCwgZGlzdF9rbm5bWzJdXSkKICAKICBwbG90IDwtIGdncGxvdCgpICsgI2dlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBjb3JyX2xpc3RbW2ldXSwgCiAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgIHkgPSBjb3JyX2xpc3RbWzFdXSksIGFscGhhID0gLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzdF9rbm5bWzFdXSwgeSA9IGNvcnJfbGlzdFtbMV1dKSkgKwogIGdlb21fbGluZShhZXMoeCA9IGRpc3Rfa25uW1sxXV0sIHkgPSBkaXN0X2tubltbMV1dKSwgY29sID0gInJlZCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiAmIHAyZyBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgIHRpdGxlID0gcGFzdGUwKG1vZGVsLCAiS05OIGFnZ3JlZ2F0ZXMiKSwKICAgICAgICB5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiAmIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIikKICBwcmludChwbG90KQp9CgpgYGAKCgojIyBTRUFjZWxscyAKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQojIHByZXBhcmUgbGlzdHMgdG8gc3RvcmUgY29ycmVsYXRpb24gdmVjdG9ycyBhbmQgY29ycmVsYXRpb24gaGlzdG9ncmFtcwpjb3JyX2xpc3QgPC0gbGlzdChzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXSwgc2VhY2VsbF9jb3JyX3AyZ1tbMV1dKQoKIyBjb21wdXRlIHRoZSBkaXN0YW5jZS13ZWlnaHRlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBmcm9tIHAyZyBsaW5rcyB1c2luZyBkaWZmZXJlbnQgCiMgZGlzdGFuY2Ugd2VpZ2h0IG1vZGVscwpmb3IgKG1vZGVsIGluIG1vZGVsX2xpc3QpewogIHdlaWdodGVkX3Njb3JlcyA8LSBkaXN0YW5jX3dlaWdodGVkX2dlbmVfYWN0aXZpdHlfc2NvcmVzKHAyZ19tYXRfc3ViLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lTW9kZWwgPSBtb2RlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gNTAwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVha19tYXQgPSBwZWFrX21hdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5rcyA9IGxpbmtzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMmdfb3JpZ2luYWwgPSBwMmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVfZXhwciA9IGdlbmVfZXhwcikKICBhZ2dfZGlzdCA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKHdlaWdodGVkX3Njb3Jlcywgc2VhY2VsbHMpCiAgZGlzdF9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMoc2VhY2VsbF9ybmFfYWdnLCBhZ2dfZGlzdCwgbmFtZSA9IHBhc3RlMCgiUDJnIGFjdGl2aXR5IHNjb3JlcywgZGlzdGFuY2Ugd2VpZ2h0ZWQsIG1vZGVsID0gIiwgbW9kZWwpKQogIHN0b3BpZm5vdChhbnkoaXMubmEoZGlzdF9rbm4pKSA9PSBGQUxTRSkKICAKICBjb3JyX2xpc3QgPC0gYXBwZW5kKGNvcnJfbGlzdCwgZGlzdF9rbm5bWzFdXSkKICBwcmludChkaXN0X2tubltbMl1dKQogICNjb3JyX3Bsb3RzX2xpc3QgPC0gYXBwZW5kKGNvcnJfcGxvdHNfbGlzdCwgZGlzdF9rbm5bWzJdXSkKICAKICBwbG90IDwtIGdncGxvdCgpICsgI2dlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBjb3JyX2xpc3RbW2ldXSwgCiAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgIHkgPSBjb3JyX2xpc3RbWzFdXSksIGFscGhhID0gLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZGlzdF9rbm5bWzFdXSwgeSA9IGNvcnJfbGlzdFtbMV1dKSkgKwogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBkaXN0X2tubltbMV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBjb3JyX2xpc3RbWzFdXSksIGFscGhhID0gMC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gY29ycl9saXN0W1sxXV0sIHkgPSBjb3JyX2xpc3RbWzFdXSksIGNvbCA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHIuICYgcDJnIGFjdGl2aXR5IHNjb3JlcyIsCiAgICAgICAgdGl0bGUgPSBwYXN0ZTAobW9kZWwsICJTRUFDZWxscyIpLAogICAgICAgIHkgPSAiQ29ycmVsYXRpb24gZ2VuZSBleHByLiAmIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIikKICBwcmludChwbG90KQp9CgpgYGAKCgoKIyBHZW5lIHdpbmRvdywgbm8gZGlzdGFuY2Ugd2VpZ2h0cwoKVGhlcmUgYXJlIHR3byBvcHRpb25zIHdoZW4gZGVmaW5pbmcgdGhlIGdlbmUgd2luZG93LiBPbmUgb3B0aW9uIGlzIHRvIGV4dGVuZCArLy0gCjEwMGJwIHVwLSBhbmQgZG93bnN0cmVhbSBvZiB0aGUgVFNTLiBIb3dldmVyLCBzaW5jZSBnZW5lcyBoYXZlIGRpZmZlcmVudCBzaXplcywKc29tZSBnZW5lIGJvZGllcyBtaWdodCBiZSBtdWNoIGxhcmdlciB0aGFuIHRoZXNlIGdlbmUgd2luZG93cy4gVGhlIHNlY29uZCBvcHRpb24gCmlzIHRvIGV4dGVuZCB0aGUgZ2VuZSB3aW5kb3cgbm90IGZyb20gdGhlIFRTUywgYnV0IGZyb20gdGhlIHN0YXJ0IGFuZCBlbmQgY29ycmRpbmF0ZSAKb2YgdGhlIGdlbmUgYm9keSByZXNwZWN0aXZlbHkuIFRoaXMgd2F5LCBtb3JlIHBlYWtzIHdpbGwgYmUgdGFrZW4gaW50byBjb25zaWRlcmF0aW9uIAppZiBhIGdlbmUgaXMgbGFyZ2VyLCBzaW1wbHkgYmVjYXVzZSB0aGUgZ2VuZSB3aW5kb3cgd2lsbCBiZSBsYXJnZXIuIFRoZXJlZm9yZSwgCmluIEFyY2hSIHRoZXkgdXNlIGFuIGFkZGl0aW9uYWwgd2VpZ2h0IGZvciB0aGUgZ2VuZSBib2R5IHNpemUgdG8gYWNjb3VudCBmb3IgdGhpcwplZmZlY3QuIEhlcmUsIHdlIGV4dGVuZCB0aGUgZ2VuZSB3aW5kb3cgYXJvdW5kIHRoZSBUU1MuIEFzIGNhbiBiZSBzZWVuIGluIAp0aGUgcGxvdCBiZWxvdywgdGhpcyBkb2VzIG5vdCB5aWVsZCBiZXR0ZXIgcmVzdWx0cywgcHJvYmFibHksIGJlY2F1c2Ugd2UgYXJlCnJlbW92aW5nIGEgbG90IG9mIGNvcnJlbGF0aW9ucyB3aGljaCBhcmUgaGlnaCBhbmQsIHRoZXJlZm9yZSwgaW1wb3J0YW50IGZvcgp0aGUgcHJlZGljdGlvbi4gCgpUaGlzIGlzIG5vdCB3aGF0IHdvdWxkIGJlIGV4cGVjdGVkLCBzaW5jZSBzb21lIGhpZ2ggY29ycmVsYXRpb25zIHdpdGhpbgp0aGUgZ2VuZSB3aW5kb3cgYXJlIHZlcnkgbGlrZWx5IHRvIGJlIGJpb2xvZ2ljYWxseSBpbXBvcnRhbnQgYW5kIHNob3VsZApyZWNhcGl0dWxhdGUgZ2VuZSBleHByZXNzaW9uIHF1aXRlIHdlbGwuIFRoaXMgaXMgYWxzbyBzaG93biBieSB0aGUgQXJjaFIgCmdlbmUgYWN0aXZpdHkgc2NvcmVzLCB3aGljaCB1c2UgZ2VuZSB3aW5kb3cgYXMgd2VsbCB0byByZXN0cmljIHRoZSBpbmZsdWVuY2UKb2YgYWNjZXNzaWJsZSByZWdpb25zIHRvIGEgY2VydGFpbiB3aW5kb3cgYXJvdW5kIHRoZSBnZW5lJ3MgVFNTLiBPbmUgcmVhc29uCmNvdWxkIGJlIHRoYXQgdGhlIHBlYWstdG8tZ2VuZSBsaW5rcyBpZGVudGlmaWVkIGJ5IHNpbXBsZSBjb3JyZWxhdGlvbnMgYXJlCm5vdCBiaW9sb2dpY2FsbHkgbWVhbmluZ2Z1bCwgdGhlcmVmb3JlIGFsc28gdmVyeSBmYXIgYXdheSBjb3JyZWxhdGlvbnMgCmFyZSBpbXBvcnRhbnQgZm9yIHJlY2FwaXR1bGF0aW5nIGdlbmUgZXhwcmVzc2lvbi4KCiMjIEdlbmUgd2luZG93IGFyb3VuZCBUU1MKCmBgYHtyLCBmaWcud2lkdGg9MTV9CiMgQXMgaW5wdXQgZm9yIHRoaXMgZnVuY3Rpb24gaXQgaXMgYmVzdCB0byB1c2Ugb25seSB0aGUgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKY29tcHV0ZV9nZW5lX3dpbmRvd19zY29yZSA8LSBmdW5jdGlvbihwMmdfbWF0X3N1YiwgcGVha19tYXQsIGxpbmtzLCBwMmdfb3JpZ2luYWwsIGdlbmVfZXhwcil7CiAgCiAgIyBjcmVhdGUgZ2VuZSBhbm5vdGF0aW9ucyB3aXRoIHN0YXJ0IGNvb3JkaW5hdGUgb2YgZWFjaCBnZW5lCiAgIyBzdWJzZXQgdG8gY29udGFpbiBvbmx5IGdlbmVzIHdoaWNoIGFyZSBpbmNsdWRlZCBpbiBvdXIgcGVhazJnZW5lIG1hdHJpeAogIGdlbmVfYW5ubyA8LSByb3dEYXRhKGdlbmVfZXhwcikgJT4lIAogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogICAgZmlsdGVyKG5hbWUgJWluJSByb3duYW1lcyhwMmdfbWF0X3N1YikpICU+JQogICAgbXV0YXRlKHN0cmFuZCA9IGlmZWxzZShzdHJhbmQgPT0gMSwgIisiLCAiLSIpKSAlPiUKICAgIG11dGF0ZShzdGFydF9jb29yZCA9IGlmZWxzZShzdHJhbmQgPT0gIisiLCBzdGFydCwgZW5kKSkgJT4lIAogICAgcmVuYW1lKGdlbmUgPSBuYW1lKSAjJT4lIEdSYW5nZXMoKQoKICAjIGV4dGVuZCBnZW5lIHJlZ2lvbnMgKy8tIDEwMGJwIHVwLSBhbmQgZG93bnN0cmVhbSBvZiB0aGUgVFNTCiAgZ2VuZV9yZWdpb25zICA8LSByZXNpemUoZ2VuZV9hbm5vICU+JSBHUmFuZ2VzKCksIHdpZHRoID0gMSkKICBleHRlbmRlZEdlbmVSZWdpb24gPC0gKHN1cHByZXNzV2FybmluZ3MoZXh0ZW5kR1IoZ2VuZV9yZWdpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHN0cmVhbSA9IDEwMDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZG93bnN0cmVhbSA9IDEwMDAwMCkpKQogICMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCiAgcG9zX2F0YWNfZ3JhbmdlcyA8LSAgbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMV1dICAlPiUgCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBtdXRhdGUoaWR4QVRBQyA9IHNlcShucm93KC4pKSkgJT4lIAogICAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgICAjIG11dGF0ZShpZHggPSBzZXFfYWxvbmcoc2VxbmFtZXMpKSAlPiUgCiAgICAjIHVuZ3JvdXAgJT4lCiAgICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICAgIGZpbHRlcihpZHhBVEFDICVpbiUgY29sbmFtZXMocDJnX21hdF9zdWIpKSAlPiUgCiAgICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAogIAogICNUT0RPOiBGaWx0ZXIgZm9yIGdlbmVzIQogIHN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeEFUQUMpKSA9PSBkaW0ocG9zX2F0YWNfZ3JhbmdlcylbWzFdXSkKICBzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhSTkEpKSA9PSBkaW0oZ2VuZV9hbm5vKVtbMV1dKQogICNwMmdfZmlsdCA8LSBwMmdfb3JpZ2luYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKGdlbmUgJWluJSByb3duYW1lcyhwMmdfbWF0KSkKICAKICAKICAgICMgZmluZCBvdmVybGFwcGluZyBwZWFrcyBhbmQgZ2VuZSB3aW5kb3cgaW4gY2hyb21vc29tZS1hd2FyZSBmYXNoaW9uCiAgdG1wIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKGV4dGVuZGVkR2VuZVJlZ2lvbiwgcG9zX2F0YWNfZ3JhbmdlcyAlPiUgR1JhbmdlcygpKSkKICAKICBwcmludChwYXN0ZTAoIk91dCBvZiAiLCBzdWJqZWN0TGVuZ3RoKHRtcCksICIgcGVha3Mgb25seSAiLAogICAgICAgICAgICAgICBsZW5ndGgodW5pcXVlKHN1YmplY3RIaXRzKHRtcCkpKSwgIiBwZWFrcyBhcmUgZm91bmQgd2l0aGluIGdlbmUgd2luZG93IG9mIDIwMGtiLiIpKQogIAogIAogICMjIyBzb21lIHBsb3RzCiAgcDEgPC0gKHRtcCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgICAgICAgZ3JvdXBfYnkocXVlcnlIaXRzKSAlPiUgIyBnZW5lIHJlZ2lvbgogICAgICAgICBzdW1tYXJpemUobiA9IG4oKSkgJT4lICMgZ2V0IG51bWJlciBvZiBwZWFrcyBvdmVybGFwcGluZyB3aXRoIGEgZ2VuZSByZWdpb24KICAgICAgICAgZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG4pLCBiaW5zID0gMTAwLCBmaWxsPSIjNjliM2EyIikgKwogICAgICAgICBsYWJzKHRpdGxlID0gIm51bWJlciBvZiBwZWFrcyBwZXIgZ2VuZSByZWdpb24gb2Ygc2l6ZSArLy0gMTAwa2IgZnJvbSBUU1MiLAogICAgICAgICAgICAgeCA9ICJudW1iZXIgb2YgcGVha3Mgd2l0aGluIHdpbmRvdyIpKQogIAogIAogIAogICMgY29tYmluZSB0aGUgdGhyZWUgZGF0YWZyYW1lcwogIHAyZ19qb2luIDwtIGxlZnRfam9pbihsaW5rcywgYXMuZGF0YS5mcmFtZShwb3NfYXRhY19ncmFuZ2VzKSwKICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCiAgcDJnX2pvaW4gPC0gbGVmdF9qb2luKHAyZ19qb2luLCBhcy5kYXRhLmZyYW1lKGdlbmVfYW5ubyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeFJOQSIsIHN1ZmZpeCA9IGMoIi5hdGFjIiwgIi5ybmEiKSkKCiAgIyBjb21wdXRlIGRpc3RhbmNlIGFuZCBkaXN0YW5jZSB3ZWlnaHRzIAogIHAyZ19qb2luIDwtIHAyZ19qb2luICU+JSAKICAgIG11dGF0ZShkaXN0YW5jZSA9IGFicyhzdGFydF9jb29yZCAtIG1pZGRsZSkpIyAlPiUKICAgIyBtdXRhdGUoZGlzdGFuY2Vfd2VpZ2h0ID0gZXZhbChwYXJzZSh0ZXh0PWdlbmVNb2RlbCkpKQogIAogIAogIHAyIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGRpc3RhbmNlKSwgYmlucyA9IDEwMCkgKwogICAgbGFicyh0aXRsZSA9ICJEaXN0YW5jZSIsIHggPSAiZGlzdGFuY2UiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgID0gMTAwMDAwLCBjb2xvciA9ICJyZWQiKSAKCiAgCiAgIyBwMiA8LSBwMmdfam9pbiAlPiUgZ2dwbG90KCkgKwogICMgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IChkaXN0YW5jZV93ZWlnaHQpKSwgYmlucyA9IDEwMCkgKwogICMgICBzY2FsZV95X2xvZzEwKCkgKwogICMgICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIFdlaWdodHMiLCB4ID0gImRpc3RhbmNlIHdlaWdodHMiKSAKCiAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgbmNvbCA9IDIpKSMpLCAgbmNvbCA9IDIpKQogIAogIAogIAogIAogICAgCiAgIyBjcmVhdGUgYSBkYXRhZnJhbWUgb2YgYWxsIHBlYWtzIHdoaWNoIG92ZXJsYXAgdGhlaXIgY29ycmVzcG9uZGluZyBnZW5lIHdpbmRvdwogIHBlYWtzX2luX2dlbmVfd2luZG93IDwtIGRhdGEuZnJhbWUoZ2VuZSA9IGdlbmVfcmVnaW9uc1txdWVyeUhpdHModG1wKV0kZ2VuZSwgCiAgICAgICAgICAgICBwZWFrID0gKHBvc19hdGFjX2dyYW5nZXMgJT4lIEdSYW5nZXMoKSlbc3ViamVjdEhpdHModG1wKV0kaWR4QVRBQykgJT4lIAogICAgdW5pdGUocGVha19nZW5lX3dpbmRvdywgZ2VuZSwgcGVhaywgc2VwID0gIiMiLCByZW1vdmUgPSBGQUxTRSkKICAKICAjIGZpbHRlciB0aGUgcDJnIGxpbmsgZGF0YWZyYW1lIGZvciBvbmx5IHBlYWtzIHdoaWNoIGFyZSB3aXRoaW4gYSBnZW5lIHdpbmRvdwogIGNvcnJfd2luZG93IDwtIHAyZ19qb2luICU+JQogICAgdW5pdGUocGVha19nZW5lX3dpbmRvdywgZ2VuZSwgaWR4QVRBQywgc2VwID0gIiMiLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgICBmaWx0ZXIocGVha19nZW5lX3dpbmRvdyAlaW4lIHBlYWtzX2luX2dlbmVfd2luZG93JHBlYWtfZ2VuZV93aW5kb3cpIAoKCiAgIyMjIFBMT1RTCiAgCiAgcDEgPC0gY29ycl93aW5kb3cgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBDb3JyZWxhdGlvbiksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gdmFsdWVzIG9mIHBlYWtzIGZvdW5kIHdpdGhpbiBnZW5lIHdpbmRvd3MiKQogIAogIHAyIDwtIGNvcnJfd2luZG93ICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZGlzdGFuY2UpLCBiaW5zID0gMjAwLCBmaWxsID0gIiM2OWIzYTIiKSArCiAgICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzIGZvdW5kIHdpdGhpbiBnZW5lIHdpbmRvd3MgYW5kIFRTUyIpCiAgCiAgcDMgPC0gY29ycl93aW5kb3cgJT4lIAogICAgbXV0YXRlKGJpbiA9IGN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAsIGJvdW5kYXJ5PTApKSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgYW5kIENvcnJlbGF0aW9uIHdpdGhpbiBnZW5lIHdpbmRvdywgMTAwMGJwIGJpbnMiLAogICAgICAgICB4ID0gIkRpc3RhbmNlICgxMDAwYnAgYmlucykiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpIAoKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbCA9IDEpKQogIAogIAogIHAxIDwtIGdncGxvdCgpICsgCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJvd1N1bXMocDJnX21hdF9zdWIgPiAwKSksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHRpdGxlID0gIiMgcGVha3MgY29ycmVsYXRlZCB3aXRoIGVhY2ggZ2VuZSIsIAogICAgICAgICB4ID0gIm51bWJlciBvZiBwZWFrcyIsIHkgPSAibG9nMTAoY291bnQpIikgCiAgICAKICAKICBwMiA8LSBnZ3Bsb3QoKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBjb2xTdW1zKHAyZ19tYXRfc3ViID4gMCkpLCBiaW5zID0gNzAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHRpdGxlID0gIiMgZ2VuZXMgY29ycmVsYXRlZCB3aXRoIGVhY2ggcGVhayIsCiAgICAgICAgIHkgPSAibG9nMTAoY291bnQpIiwgeCA9ICJudW1iZXIgb2YgZ2VuZXMiKQogIAogIHAzIDwtIGdncGxvdCgpICsgCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJvd1N1bXMocDJnX21hdF9zdWIgPiAwKSksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiIyBwZWFrcyBjb3JyZWxhdGVkIHdpdGggZWFjaCBnZW5lIiwgCiAgICAgICAgIHggPSAibnVtYmVyIG9mIHBlYWtzIiwgeSA9ICJjb3VudCIpIAogICAgCiAgCiAgcDQgPC0gZ2dwbG90KCkgKyAKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gY29sU3VtcyhwMmdfbWF0X3N1YiA+IDApKSwgYmlucyA9IDcwLCBmaWxsID0gIiM2OWIzYTIiKSArCiAgICBsYWJzKHRpdGxlID0gIiMgZ2VuZXMgY29ycmVsYXRlZCB3aXRoIGVhY2ggcGVhayIsCiAgICAgICAgIHkgPSAiY291bnQiLCB4ID0gIm51bWJlciBvZiBnZW5lcyIpCiAgCiAgcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMikpCgogIAoKICAKICAjIAogICMgCiAgIyBwZWFrX21pZGRsZV9yZWdpb24gPC0gcG9zX2F0YWNfZ3JhbmdlcyAlPiUgR1JhbmdlcygpCiAgIyAjIGFkZCB0aGUgaGFsZiB3aWR0aCB0byB0aGUgc3RhcnQgb2YgZWFjaCBwZWFrCiAgIyBzdGFydChwZWFrX21pZGRsZV9yZWdpb24pID0gc3RhcnQocGVha19taWRkbGVfcmVnaW9uKSArIAogICMgICBmbG9vcih3aWR0aChwZWFrX21pZGRsZV9yZWdpb24pIC8gMikKICAjICMgcmVzaXplIHRoZSByYW5nZXMgc28gd2Ugb25seSBoYXZlIHRoZSBtaWRkbGUgb2YgZWFjaCBwZWFrCiAgIyBwZWFrX21pZGRsZV9yZWdpb24gPC0gcmVzaXplKHBlYWtfbWlkZGxlX3JlZ2lvbiwgMSwgInN0YXJ0IikKICAjIAogICMgIyBjb21wdXRlIHRoZSBkaXN0YW5jZXMgYmV0d2VlbiBwZWFrIG1pZGRsZSBhbmQgZ2VuZSBUU1Mgb2YgYWxsIHBlYWtzIHdoaWNoIAogICMgIyBvdmVybGFwIHdpdGggYSBnZW5lIHdpbmRvdwogICMgZGlzdGFuY2UgPC0gZGlzdGFuY2UocmFuZ2VzKGdlbmVfcmVnaW9ucylbcXVlcnlIaXRzKHRtcCldLCAKICAjICAgICAgICAgICAgICAgcmFuZ2VzKHJlc2l6ZShwZWFrX21pZGRsZV9yZWdpb24sIHdpZHRoID0gMSkpW3N1YmplY3RIaXRzKHRtcCldKQogICMgCiAgIyAKICAjICMjIyBQTE9UCiAgIyAjIHAxIDwtIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBkaXN0YW5jZSksIGJpbnMgPSAyMDApICsKICAjICMgICBzY2FsZV95X2xvZzEwKCkgKwogICMgIyAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrIG1pZGRsZSBhbmQgZ2VuZSBUU1Mgd2l0aGluIGEgZ2VuZSB3aW5kb3ciLAogICMgIyAgICAgICAgeSA9ICJsb2cxMChjb3VudCkiKSArCiAgIyAjICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTAwMDAwLCBjb2xvciA9ICJyZWQiKQogICMgCiAgIyAKICAjIAogICMgaXNNaW51cyA8LSBCaW9jR2VuZXJpY3M6OndoaWNoKHN0cmFuZChnZW5lX3JlZ2lvbnMpID09ICItIikKICAjICMgc3VidHJhY3QgdGhlIGdlbmUgc3RhcnQgY29vcmRpbmF0ZSBmcm9tIHRoZSB0aWxlIHN0YXJ0IGNvb3JkaW5hdGUgLT4gcmVsYXRpdmUgZGlzdGFuY2VzCiAgIyBzaWduRGlzdCA8LSBzaWduKHN0YXJ0KHBlYWtfbWlkZGxlX3JlZ2lvbilbc3ViamVjdEhpdHModG1wKV0gLSAKICAjICAgICAgICAgICAgICAgICAgICBzdGFydChyZXNpemUoZ2VuZV9yZWdpb25zLDEsInN0YXJ0IikpW3F1ZXJ5SGl0cyh0bXApXSkKICAjICMgY29udmVydCB0aGUgZGlyZWN0aW9uIG9mIGRpc3RhbmNlIGZvciBhbGwgZGlzdGFuY2VzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIG5lZ2F0aXZlIHN0cmFuZAogICMgc2lnbkRpc3RbaXNNaW51c10gPC0gc2lnbkRpc3RbaXNNaW51c10gKiAtMQogICMgCiAgIyAKICAjIGRpc3RhbmNlIDwtIGRpc3RhbmNlICogc2lnbkRpc3QKICAjIAogICMgCiAgIyAKICAjICMjIyMgUExPVAogICMgcDIgPC0gZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IGRpc3RhbmNlKSwgYmlucyA9IDUwMCkgKyAKICAjICAgc2NhbGVfeV9sb2cxMCgpICsKICAjICAgbGFicyh0aXRsZSA9ICJSZWxhdGl2ZSBkaXN0YW5jZSBvZiBwZWFrcyB0byBUU1Mgd2l0aGluIGEgZ2VuZSB3aW5kb3ciLAogICMgICAgICAgIHggPSAiUmVsYXRpdmUgZGlzdGFuY2UgdG8gVFNTIiwgeSA9ICJsb2cxMChjb3VudCkiKSArIAogICMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEwMDAwMCwgLTEwMDAwMCksIGNvbG9yID0gInJlZCIpCiAgIyAKICAjIHByaW50KHAyKQogICMgI2Nvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAxKQoKICBwMmdfbGlua3NfZ2VuZV93aW5kb3cgPC0gTWF0cml4OjpzcGFyc2VNYXRyaXgoCiAgICAgIGkgPSBjb3JyX3dpbmRvdyRpZHhSTkEsIAogICAgICBqID0gY29ycl93aW5kb3ckaWR4QVRBQywgCiAgICAgIHggPSBjb3JyX3dpbmRvdyRDb3JyZWxhdGlvbiwgCiAgICAgIGRpbXMgPSBjKG5yb3coZXhwcl9tYXQpLCBucm93KHBlYWtfbWF0KSksCiAgICAgIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhleHByX21hdCkscm93bmFtZXMocGVha19tYXQpKQogICAgKQogIAogIHByaW50KHBhc3RlMCgiVGhlIHBlYWstdG8tZ2VuZSBsaW5rcyBtYXRyaXgsIHJlc3RyaWN0ZWQgdG8gYSArLy0gMTAwa2Igd2luZG93IGFyb3VuZCB0aGUgVFNTIGhhcyBkaW1lbnNpb25zICIsIHNwbGl0KGRpbShwMmdfbGlua3NfZ2VuZV93aW5kb3cpLCAxKSkpCiAgCiAgcHJpbnQocGFzdGUwKCJUaGUgbWF4aW11bSB2YWx1ZSBpczogIiwgbWF4KHAyZ19saW5rc19nZW5lX3dpbmRvdyksICIsIHRoZSBtaW51bSB2YWx1ZSBpczogIiwgbWluKHAyZ19saW5rc19nZW5lX3dpbmRvdykgKSkKICAKICAKICAKICBwMmdfbGlua3NfZ2VuZV93aW5kb3cgPC0gcDJnX2xpbmtzX2dlbmVfd2luZG93W3Jvd1N1bXMocDJnX2xpbmtzX2dlbmVfd2luZG93KSAhPSAwLCBdCiAgcDJnX2xpbmtzX2dlbmVfd2luZG93IDwtIHAyZ19saW5rc19nZW5lX3dpbmRvd1ssIGNvbFN1bXMocDJnX2xpbmtzX2dlbmVfd2luZG93KSAhPSAwXQogIAogIHByaW50KHBhc3RlMCgiQWZ0ZXIgcmVtb3ZpbmcgYW55IHJvd3MgYW5kIGNvbHVtc24gd2hpY2ggZG8gbm90IGNvbnRhaW4gYW55IGxpbmtzIHdlIGFyZSBsZWZ0IHdpdGggIiwgbnJvdyhwMmdfbGlua3NfZ2VuZV93aW5kb3cpLCAiIGdlbmVzIGFuZCAiLCBuY29sKHAyZ19saW5rc19nZW5lX3dpbmRvdyksICIgcGVha3MuIikpCiAgIyBDb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzCiAgZ2VuZV93aW5kb3dfc2NvcmVzIDwtIGdlbmVfYWN0aXZpdHlfc2NvcmVzKHBlYWtfbWF0X3N1Yltjb2xuYW1lcyhwMmdfbGlua3NfZ2VuZV93aW5kb3cpLCBdLCBwMmdfbGlua3NfZ2VuZV93aW5kb3cpCiAgZGltKGdlbmVfd2luZG93X3Njb3JlcykKCiAgCiAgcmV0dXJuKGdlbmVfd2luZG93X3Njb3JlcykgCn0KYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQpnZW5lX3dpbmRvd19zY29yZXMgPC0gY29tcHV0ZV9nZW5lX3dpbmRvd19zY29yZSgKICBwMmdfbWF0X3N1YiA9IHAyZ19tYXRfc3ViLCAKICBwZWFrX21hdCA9IHBlYWtfbWF0LCAKICBsaW5rcyA9IGxpbmtzLCAKICBwMmdfb3JpZ2luYWwgPSBwMmcsIAogIGdlbmVfZXhwciA9IGdlbmVfZXhwcikKYGBgCgojIyMgS05OIGFnZ3JlZ2F0ZXMKCkZpcnN0LCBJIGNvbXBhcmVkIHRoZSBkaXN0YW5jZSB3ZWlndGhlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBiYXNlZCBvbiB0aGUgQXJjaFIgS05OIGFnZ3JlZ2F0ZXMuIAoKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQp3ZWlnaHRlZF9zY29yZXNfYWdnIDwtIGtubl9hZ2dyZWdhdGVzKGdlbmVfd2luZG93X3Njb3JlcywgY2VsbF9hZ2dfbGlzdCkKd2VpZ2h0ZWRfa25uX2NvcnIgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgd2VpZ2h0ZWRfc2NvcmVzX2FnZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlAyZyBsaW5rcyB3aXRoaW4gZ2VuZSB3aW5kb3ciKQp3ZWlnaHRlZF9rbm5fY29ycltbMl1dCgpnZ3Bsb3QoKSArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IHdlaWdodGVkX2tubl9jb3JyW1sxXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhcmNocl9rbm5bWzFdXVtuYW1lcyh3ZWlnaHRlZF9rbm5fY29ycltbMV1dKV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB3ZWlnaHRlZF9rbm5fY29ycltbMV1dLCB5ID0gYXJjaHJfa25uW1sxXV1bbmFtZXMod2VpZ2h0ZWRfa25uX2NvcnJbWzFdXSldKSkgKwogIGdlb21fbGluZShhZXMoeCA9IHdlaWdodGVkX2tubl9jb3JyW1sxXV0sIHkgPSB3ZWlnaHRlZF9rbm5fY29ycltbMV1dKSwgY29sID0gInJlZCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBwMmcgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgICB0aXRsZSA9ICJQZWFrLXRvLWdlbmUgbGlua3MgYXJlIHJlc3RyaWN0ZWQgdG8gYSBnZW5lIHdpbmRvdyBvZiArLy0gMTAwa2IgYXJvdW5kIFRTUyIsCiAgICAgICAgeSA9ICJDb3JyZWxhdGlvbiBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMiKQoKCgpgYGAKCgojIyMgU0VBQ2VsbHMKClNlY29uZCwgSSBjb21wYXJlZCB0aGUgZGlzdGFuY2Ugd2VpZ3RocyB1c2luZyB0aGUgU0VBQ2VsbCBhZ2dyZWdhdGVzLCB3aGljaAp5aWVsZHMgYmV0dGVyIHJlc3VsdHMgYXMgY2FuIGJlIHNlZW4gYWJvdmUuIAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9CmdlbmVfd2luZG93X2FnZyA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKGdlbmVfd2luZG93X3Njb3Jlcywgc2VhY2VsbHMpCmdlbmVfd2luZG93X2NvcnIgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMoc2VhY2VsbF9ybmFfYWdnLCBnZW5lX3dpbmRvd19hZ2csCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJHZW5lIHdpbmRvdyBhcm91bmQgVFNTIikKCmdlbmVfd2luZG93X2NvcnJbWzJdXQoKCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZ2VuZV93aW5kb3dfY29ycltbMV1dLAogICAgICAgICAgICAgICAgIHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSkpICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcygKICAgIHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwKICAgIHggPSBnZW5lX3dpbmRvd19jb3JyW1sxXV0pLCBhbHBoYSA9IDAuNSkgKwogIGdlb21fbGluZShhZXMoeCA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dW25hbWVzKGdlbmVfd2luZG93X2NvcnJbWzFdXSldLCAKICAgICAgICAgICAgICAgIHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSksIAogICAgICAgICAgICBjb2xvciA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgcDJnIGFjdGl2aXR5IHNjb3JlcywgZ2VuZSB3aW5kb3ciLAogICAgICAgIHkgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBnZW5lIGV4cHJlc3Npb24gYW5kIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgIHRpdGxlID0gIlBlYWstdG8tZ2VuZSBsaW5rcyB3aXRoaW4gZ2VuZSB3aW5kb3ciKQoKYGBgCgojIEVmZmVjdCBvZiB1c2luZyBkaWZmZXJlbnQgZGlzdGFuY2UgZGVjYXkgcmF0ZXMgCgpIb3cgZG9lcyB0aGUgZGlzdGFuY2Ugd2VpZ2h0IGRpc3RyaWJ1dGlvbiBjaGFuZ2Ugd2l0aCBkaWZmZXJlbnQgZGVjYXkgcmF0ZXM/CgpIZXJlLCB3ZSB1c2UgdGhlIGZvcm11bGEgJGVee1xmcmFjey1hYnMoZGlzdGFuY2UpfXtjfX0kIHdpdGggZGlmZmVyZW4gZGVjYXkgcmF0ZXMKJGMgXGluIFx7NTAwMCwgNTAwMDAsIDUwMDAwMCwgNTAwMDAwMFx9JC4gQWRkaXRpb25hbGx5LCB3ZSB1c2Ugb25seSBwZWFrcyB3aGljaCAKb3ZlcmxhcCB3aXRoIGEgKy8tIDEwMGtiIHdpbmRvdyBmcm9tIHRoZSBUU1MuCgpgYGB7ciwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NX0KbW9kZWxfbGlzdCA8LSBjKCJleHAoLWFicyhkaXN0YW5jZSkvNTAwMCkiLCAiZXhwKC1hYnMoZGlzdGFuY2UpLzUwMDAwKSIsCiAgICAgICAgICAgICAgICAiZXhwKC1hYnMoZGlzdGFuY2UpLzUwMDAwMCkiLCAiZXhwKC1hYnMoZGlzdGFuY2UpLzUwMDAwMDApIikKCgphdGFjX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnKVtbMV1dCiNybmFfZ3JhbmdlcyA8LSBtZXRhZGF0YShwMmdfb3JpZ2luYWwpW1syXV0KZ2VuZV9hbm5vIDwtIHJvd0RhdGEoZ2VuZV9leHByKQoKIyBjcmVhdGUgZ2VuZSBhbm5vdGF0aW9ucyB3aXRoIHN0YXJ0IGNvb3JkaW5hdGUgb2YgZWFjaCBnZW5lCiMgc3Vic2V0IHRvIGNvbnRhaW4gb25seSBnZW5lcyB3aGljaCBhcmUgaW5jbHVkZWQgaW4gb3VyIHBlYWsyZ2VuZSBtYXRyaXgKZ2VuZV9hbm5vIDwtIGdlbmVfYW5ubyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhSTkEgPSBzZXEobnJvdyguKSkpICU+JSAKICBmaWx0ZXIobmFtZSAlaW4lIHJvd25hbWVzKHAyZ19tYXRfc3ViKSkgJT4lCiAgbXV0YXRlKHN0cmFuZCA9IGlmZWxzZShzdHJhbmQgPT0gMSwgIisiLCAiLSIpKSAlPiUKICBtdXRhdGUoc3RhcnRfY29vcmQgPSBpZmVsc2Uoc3RyYW5kID09ICIrIiwgc3RhcnQsIGVuZCkpICU+JSAKICByZW5hbWUoZ2VuZSA9IG5hbWUpICMlPiUgR1JhbmdlcygpCgojIHN1YnNldCBhdGFjIGdyYW5nZXMgJiBnZXQgbWlkZGxlIG9mIGVhY2ggcGVhawpwb3NfYXRhY19ncmFuZ2VzIDwtIGF0YWNfZ3JhbmdlcyAgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoaWR4QVRBQyA9IHNlcShucm93KC4pKSkgJT4lIAogICMgZ3JvdXBfYnkoc2VxbmFtZXMpICU+JQogICMgbXV0YXRlKGlkeCA9IHNlcV9hbG9uZyhzZXFuYW1lcykpICU+JSAKICAjIHVuZ3JvdXAgJT4lCiAgI3RpZHlyOjp1bml0ZShjaHJfaWR4LCBzZXFuYW1lcywgaWR4LCByZW1vdmUgPSBGQUxTRSwgc2VwID0gIl8iKSAlPiUgCiAgZmlsdGVyKGlkeEFUQUMgJWluJSBjb2xuYW1lcyhwMmdfbWF0X3N1YikpICU+JSAKICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAoKCgojIGNvbWJpbmUgdGhlIHRocmVlIGRhdGFmcmFtZXMKcDJnX2pvaW4gPC0gbGVmdF9qb2luKGxpbmtzLCBhcy5kYXRhLmZyYW1lKHBvc19hdGFjX2dyYW5nZXMpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCnAyZ19qb2luIDwtIGxlZnRfam9pbihwMmdfam9pbiwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm8pLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4Uk5BIiwgc3VmZml4ID0gYygiLmF0YWMiLCAiLnJuYSIpKQoKIyBjb21wdXRlIGRpc3RhbmNlIGFuZCBkaXN0YW5jZSB3ZWlnaHRzIApwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgbXV0YXRlKGRpc3RhbmNlID0gYWJzKHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKSkgJT4lCiAgbXV0YXRlKHJlbF9kaXN0YW5jZSA9IHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKQogIyBtdXRhdGUoZGlzdGFuY2Vfd2VpZ2h0ID0gZXZhbChwYXJzZSh0ZXh0PWdlbmVNb2RlbCkpKQoKZm9yIChtb2RlbCBpbiBtb2RlbF9saXN0KXsgCiMgY29tcHV0ZSBkaXN0YW5jZSBhbmQgZGlzdGFuY2Ugd2VpZ2h0cyAKICBwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoc3RhcnRfY29vcmQgLSBtaWRkbGUpKSAlPiUKICAgIG11dGF0ZShkaXN0YW5jZV93ZWlnaHQgPSBldmFsKHBhcnNlKHRleHQ9bW9kZWwpKSkKICAKICBwMSA8LSBwMmdfam9pbiAlPiUgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBkaXN0YW5jZSksIGJpbnMgPSAyMDAsIGZpbGw9IiM2OWIzYTIiKSArCiAgICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzIiwgeCA9ICJkaXN0YW5jZSIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCAgPSA1MDAwLCBjb2xvciA9ICJyZWQiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgID0gMjUwMDAwLCBjb2xvciA9ICJvcmFuZ2UiKQogIAogIHAyIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IChkaXN0YW5jZV93ZWlnaHQpKSwgYmlucyA9IDIwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKCJEaXN0YW5jZV9kZWNheTogIiwgbW9kZWwpLAogICAgICAgICB4ID0gImRpc3RhbmNlIHdlaWdodHMiLCB5ID0gImxvZzEwKGNvdW50cykiKQogIAogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAyKSkKCn0KICAjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiB2YWx1ZQojIHAzIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiMgICBnZW9tX3BvaW50KGFlcyh4ID0gQ29ycmVsYXRpb24sIHkgPSBkaXN0YW5jZSkpICsKIyAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgdnMuIGNvcnJlbGF0aW9uIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzIiwKIyAgICAgICAgeCA9ICJDb3JyZWxhdGlvbiBiZXR3ZWVuIHBlYWsgYW5kIGdlbmUiLCAKIyAgICAgICAgeSA9ICJEaXN0YW5jZSBiZXR3ZWVuIHBlYWsgYW5kIGdlbmUiKQojIAojIAojIHA0IDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArCiMgICBnZW9tX3BvaW50KGFlcyh4ID0gQ29ycmVsYXRpb24sIHkgPSBkaXN0YW5jZV93ZWlnaHQpKSArCiMgICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIHZzLiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBlYWtzIGFuZCBnZW5lcyIsCiMgICAgICAgIHggPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBwZWFrIGFuZCBnZW5lIiwgCiMgICAgICAgIHkgPSAiRGlzdGFuY2Ugd2VpZ2h0cyBiZXR3ZWVuIHBlYWsgYW5kIGdlbmUiKQoKCiNjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMSkKCmBgYAoKCiMjIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gdmFsdWVzCgpgYGAje3IsZmlnLndpZHRoPTE1fQoKIyBPbG90IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBhcyBkZW5zaXR5IHBsb3RzCnAxIDwtIHAyZ19qb2luICU+JSBnZ3Bsb3QoKSArIAogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSBDb3JyZWxhdGlvbiwgeSA9IGRpc3RhbmNlKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgKwogIGxhYnModGl0bGUgPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYW5kIGNvcnJlbGF0aW9uIikKCnAyIDwtIHAyZ19qb2luICU+JQogIGZpbHRlcihDb3JyZWxhdGlvbiA+IDAuMykgJT4lIAogIGdncGxvdCgpICsgCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeCA9IENvcnJlbGF0aW9uLCB5ID0gZGlzdGFuY2UpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24iKQoKcDMgPC0gcDJnX2pvaW4gJT4lCiAgZmlsdGVyKENvcnJlbGF0aW9uID4gMC42KSAlPiUgCiAgZ2dwbG90KCkgKyAKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gQ29ycmVsYXRpb24sIHkgPSBkaXN0YW5jZSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiIpCgpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbCA9IDIpCmBgYAoKCmBgYCN7cn0KcDJnICU+JSAgCiAgbXV0YXRlKGJpbj1jdXRfd2lkdGgoZGlzdGFuY2UsIHdpZHRoPTEwMDAwMCwgYm91bmRhcnk9MCkpICU+JQogIGZpbHRlcihkaXN0YW5jZSA8IDEwMDAwMDAwKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbD0iIzY5YjNhMiIpICsKICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ICA9IDI1MDAwMCwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiUmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYW5kIGNvcnJlbGF0aW9uIG9mIHAyZyBsaW5rcywgMTAwa2IgYmlucyIsCiAgICAgICB4ID0gIkRpc3RhbmNlIGJldHdlZW4gcGVha3MgYW5kIGdlbmVzIHdpdGhpbiAyNTBrYiIsIHkgPSAiQ29ycmVsYXRpb24iKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMH0KcDJnX2pvaW4gJT4lICAKICBtdXRhdGUoYmluPWN1dF93aWR0aChkaXN0YW5jZSwgd2lkdGg9MTAwMDAwLCBib3VuZGFyeT0wKSkgJT4lCiAgZmlsdGVyKGRpc3RhbmNlIDwgMTAwMDAwMDApICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gYmluLCB5ID0gQ29ycmVsYXRpb24pLCBmaWxsPSIjNjliM2EyIikgKwogICNnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgID0gMjUwMDAwLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxMDBrYiBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMgd2l0aGluIDI1MGtiIiwgeSA9ICJDb3JyZWxhdGlvbiIpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjIsIGZpZy5oZWlnaHQ9MTV9CgpwMSA8LSBwMmdfam9pbiAlPiUgIAogIG11dGF0ZShiaW49Y3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDAwMCAmIENvcnJlbGF0aW9uID4gMC41KSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbD0iIzY5YjNhMiIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBvZiBwMmcgbGlua3MsIDEwMGtiIGJpbnMiLAogICAgICAgeCA9ICJEaXN0YW5jZSA8IDFlXjcgYnAiLCB5ID0gIkNvcnJlbGF0aW9uID4gMC41IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgpwMiA8LSBwMmdfam9pbiAlPiUgIAogIG11dGF0ZShiaW49Y3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDAwMCAmIENvcnJlbGF0aW9uID4gMC44KSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbD0iIzY5YjNhMiIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBvZiBwMmcgbGlua3MsIDEwMGtiIGJpbnMiLAogICAgICAgeCA9ICJEaXN0YW5jZSA8IDFlXjcgYnAiLCB5ID0gIkNvcnJlbGF0aW9uID4gMC44IikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgpwMyA8LSBwMmdfam9pbiAlPiUgIAogIG11dGF0ZShiaW49Y3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDAwMCAmIENvcnJlbGF0aW9uIDwgMC41KSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbD0iIzY5YjNhMiIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBvZiBwMmcgbGlua3MsIDEwMGtiIGJpbnMiLAogICAgICAgeCA9ICJEaXN0YW5jZSA8IDFlXjcgYnAiLCB5ID0gIkNvcnJlbGF0aW9uIDwgMC41IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgoKCnA0IDwtIHAyZ19qb2luICU+JSAgCiAgbXV0YXRlKGJpbj1jdXRfd2lkdGgoZGlzdGFuY2UsIHdpZHRoPTEwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDAgJiBDb3JyZWxhdGlvbiA+IDAuNSkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGw9IiM2OWIzYTIiKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBhbmQgY29ycmVsYXRpb24gb2YgcDJnIGxpbmtzLCAxa2IgYmlucyIsCiAgICAgICB4ID0gIkRpc3RhbmNlIDwgMTAwa2IiLCB5ID0gIkNvcnJlbGF0aW9uID4gMC41IikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgoKY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBuY29sID0gMikKYGBgCgpMZXRzIGhhdmUgYSBsb29rIGF0IGNvcnJlbGF0aW9uIHZhbHVlcyBiZXR3ZWVuIHBlYWtzIHdpdGhpbiB0aGUgcHJvbW90ZXIgcmVnaW9uCm9mIGEgVFNTLCBuYW1lbHkgNWtiIHVwc3RyZWFtIG9mIHRoZSBUU1MuCgpgYGB7ciwgZmlnLndpZHRoPTh9CnAyZ19qb2luICU+JSAgCiAgbXV0YXRlKGJpbj1jdXRfd2lkdGgocmVsX2Rpc3RhbmNlLCB3aWR0aD0xMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIocmVsX2Rpc3RhbmNlIDwgMCAmIHJlbF9kaXN0YW5jZSA+PSAtNTAwMCkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGw9IiM2OWIzYTIiKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCAgPSAyNTAwMDAsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIC01a2IgdXBzdHJlYW0gb2YgVFNTLCAxMDBicCBiaW5zIiwKICAgICAgIHggPSAiRGlzdGFuY2UgLTVrYiB1cHN0cmVhbSBvZiBUU1MiLCB5ID0gIkNvcnJlbGF0aW9uIikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCmBgYAoKCiMjIyBUcnkgZGlzdGFuY2UgZGVjYXkgcmF0ZXMKCgpgYGB7cn0Kcm5hX2tubiA8LSByZWFkUkRTKCIxMV9hZGRlZF9SaWNhcmRzX3BlYWtzX3AyZ19lbnRpcmVfY2hyb21vc29tZS9QZWFrMkdlbmVMaW5rcy9zZVJOQS1Hcm91cC1LTk4ucmRzIikKI3JuYV9hZ2dfbWF0IDwtIGFzc2F5cyhybmFfa25uKVtbMV1dCiNyb3duYW1lcyhybmFfYWdnX21hdCkgPC0gcm93RGF0YShybmFfa25uKSRuYW1lCgpjZWxsX2FnZ19saXN0IDwtIG1ldGFkYXRhKHJuYV9rbm4pW1sxXV0KCgprbm5fYWdncmVnYXRlcyA8LSBmdW5jdGlvbihtYXRyaXgsIGNlbGxfYWdnX2xpc3QpewogICMgZW1wdHkgbWF0cml4IHRvIHN0b3JlIGFnZ3JlZ2F0ZXMKICBhZ2cgPC0gbWF0cml4KGRhdGEgPSAwLAogICAgICAgICAgICAgICAgbnJvdyA9IGRpbShtYXRyaXgpWzFdLAogICAgICAgICAgICAgICAgbmNvbCA9IGxlbmd0aChjZWxsX2FnZ19saXN0KSwKICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChyb3duYW1lcyhtYXRyaXgpLCBOVUxMKSkKICAKICBmb3IgKGkgaW4gc2VxLmludChsZW5ndGgoY2VsbF9hZ2dfbGlzdCkpKSB7CiAgICBhZ2dbLCBpXSA8LSByb3dTdW1zKG1hdHJpeFssIGNlbGxfYWdnX2xpc3RbW2ldXV0pCiAgfQogIHJldHVybihhZ2cpCn0KCgpybmFfYWdnIDwtIGtubl9hZ2dyZWdhdGVzKGV4cHJfbWF0X3N1YiwgY2VsbF9hZ2dfbGlzdCkKYXJjaHJfa25uIDwtIGFyY2hyX3Njb3Jlc19tYXRbYXMudmVjdG9yKHJvd25hbWVzKGFnZ19wMmdfa25uKSksXQphZ2dfYXJjaHJfa25uIDwtIGtubl9hZ2dyZWdhdGVzKGFyY2hyX2tubiwgY2VsbF9hZ2dfbGlzdCkKCmFnZ19wMmdfa25uIDwtIGtubl9hZ2dyZWdhdGVzKHAyZ19zY29yZXMsIGNlbGxfYWdnX2xpc3QpCmFnZ19kaXN0IDwtIGtubl9hZ2dyZWdhdGVzKHdlaWdodGVkX3Njb3JlcywgY2VsbF9hZ2dfbGlzdCkKYGBgCgoKYGBge3IsIGZpZy53aWR0aD0xMH0KYXJjaHJfa25uIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHJuYV9hZ2csIGFnZ19hcmNocl9rbm4sICJBcmNociBnZW5lIGFjdGl2aXR5IHNjb3JlcyIpCnAyZ19rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX3AyZ19rbm4sICJQZWFrLXRvLWdlbmUgbGlua3MgYWN0aXZpdHkgc2NvcmVzIikKZGlzdF9rbm4gPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2FnZywgYWdnX2Rpc3QsICJQZWFrLXRvX2dlbmUgbGlua3MgYWN0aXZpdHkgc2NvcmVzIHdlaWdodGVkIGJ5IGRpc3RhbmNlIikKY293cGxvdDo6cGxvdF9ncmlkKGFyY2hyX2tubltbMl1dLCBwMmdfa25uW1syXV0sIGRpc3Rfa25uW1syXV0sIG5jb2wgPSAyKQoKcDEgPC0gZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gcDJnX2tubltbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYXJjaHJfa25uW1sxXV0pLCBhbHBoYSA9IC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHAyZ19rbm5bWzFdXSwgeSA9IGFyY2hyX2tubltbMV1dKSkgKwogIGdlb21fbGluZShhZXMoeCA9IHAyZ19rbm5bWzFdXSwgeSA9IHAyZ19rbm5bWzFdXSksIGNvbCA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAKICAKICAKcDIgPC0gZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gZGlzdF9rbm5bWzFdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFyY2hyX2tubltbMV1dKSwgYWxwaGEgPSAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBkaXN0X2tubltbMV1dLCB5ID0gYXJjaHJfa25uW1sxXV0pKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gZGlzdF9rbm5bWzFdXSwgeSA9IGRpc3Rfa25uW1sxXV0pLCBjb2wgPSAicmVkIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgCgpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMikKYGBgCgoKCiMgVEFEIGJvdW5kYXJpZXMKCkluIGNhc2UgSGktQyBkYXRhIGFyZSBhdmFpbGFibGUsIFRBRCBib3VuZGFyaWVzIGNvdWxkIGFpZCBpbiBmaW5kaW5nIApwZWFrLXRvLWdlbmUgbGlua3MuIFNldHRpbmcgYSBkaXN0YW5jZSBkZWNheSByYXRlIHRvIHRoZSBzYW1lIHZhbHVlCmZvciBhbGwgZ2VuZXMgYW5kIGNlbGx0eXBlcywgZG9lcyBub3QgZ2l2ZSBjcmVkaXQgdG8gdGhlIGJpb2xvZ2ljYWwgdmFyaWFiaWxpdHkgYXNzb2NpYXRlZCB3aXRoIGdlbmUgcmVndWxhdGlvbi4gSW4gW0BadWluMjAyMl0gaXQgaGFzIGJlZW4Kc2hvd24gZXhwZXJpbWVudGFsbHksIHRoYXQgaW50ZXJhY3Rpb25zIGJldHdlZW4gcmVndWxhdG9yeSBlbGVtZW50cyAKZGVjYXkgZXhwb25lbnRpYWxseSB3aXRoaW4gVEFEIGJvdW5kYXJpZXMgYW5kIGFsbW9zdCBkaXNhcHBlYXIgY29tcGxldGVseSBiZXlvbmQgVEFEIGJvdW5kYXJpZXMuIEhlcmUsIEkgcmVzdHJpY3RlZCB0aGUgcGVhay10by1nZW5lIGxpbmtzIGlkZW50aWZpZWQgYnkgQXJjaFIgdG8gd2l0aGluIFRBRCBib3VuZGFyaWVzIGFuZCBjb21wdXRlZCBnZW5lIGFjdGl2aXR5IHNjb3JlcyBhZ2Fpbi4KCmBgYHtyfQp0YWRfYm91bmRhcmllcyA8LSBhcy5kYXRhLmZyYW1lKHJlYWQudGFibGUoImp1cHl0ZXJfbm90ZWJvb2tzL3RhZF9lNzUuYmVkIiwgaGVhZGVyID0gRkFMU0UsIHNlcCA9ICJcdCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgcXVvdGUgPSAiIikpCnRhZF9ib3VuZGFyaWVzIDwtIHRhZF9ib3VuZGFyaWVzICU+JSAKICByZW5hbWUoc2VxbmFtZXMgPSBWMSwgc3RhcnQgPSBWMiwgZW5kID0gVjMpICU+JSAKICBHUmFuZ2VzKCkKCnAxIDwtIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSB3aWR0aChnZW5lX2Fubm8gJT4lIEdSYW5nZXMoKSkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlucyA9IDIwMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbih3aWR0aChnZW5lX2Fubm8gJT4lIEdSYW5nZXMoKSkpLCAKICAgICAgICAgICAgIGNvbG9yID0gIm9yYW5nZSIpICsKICBsYWJzKHRpdGxlID0gcGFzdGUwKCJEaXN0cmlidXRpb24gb2YgZ2VuZSBzaXplLCBtZWRpYW4gc2l6ZSA9ICIsCiAgICAgICAgICAgICAgICAgICAgICBtZWRpYW4od2lkdGgoZ2VuZV9hbm5vICU+JSBHUmFuZ2VzKCkpKSksCiAgICAgICB4ID0gIkdlbmUgc2l6ZSBpbiBicCIpCgpwMiA8LSBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gd2lkdGgodGFkX2JvdW5kYXJpZXMpKSwgYmlucyA9IDIwMCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbih3aWR0aCh0YWRfYm91bmRhcmllcykpLCBjb2xvciA9ICJvcmFuZ2UiKSArCiAgbGFicyh0aXRsZSA9IHBhc3RlMCgiRGlzdHJpYnV0aW9uIG9mIFRBRCBib3VuZGFyeSBzaXplLCBtZWRpYW4gc2l6ZSA9ICIsCiAgICAgICBtZWRpYW4od2lkdGgodGFkX2JvdW5kYXJpZXMpKSksCiAgICAgIHggPSAiVEFEIGJvdW5kYXJ5IHNpemUgaW4gYnAiKQoKY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgbmNvbCA9IDEpCmBgYAoKV2hhdCBpcyB0aGUgZGlzdHJpYnV0aW9uIG9mIHBlYWtzIGFuZCBnZW5lcyB3aXRoaW4gVEFEIGJvdW5kYXJpZXM/CgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTV9CmdlbmVfYW5ubyA8LSByb3dEYXRhKGdlbmVfZXhwcikKCiMgY3JlYXRlIGdlbmUgYW5ub3RhdGlvbnMgd2l0aCBzdGFydCBjb29yZGluYXRlIG9mIGVhY2ggZ2VuZQojIHN1YnNldCB0byBjb250YWluIG9ubHkgZ2VuZXMgd2hpY2ggYXJlIGluY2x1ZGVkIGluIG91ciBwZWFrMmdlbmUgbWF0cml4CmdlbmVfYW5ubyA8LSBnZW5lX2Fubm8gJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBtdXRhdGUoaWR4Uk5BID0gc2VxKG5yb3coLikpKSAlPiUgCiAgZmlsdGVyKG5hbWUgJWluJSByb3duYW1lcyhwMmdfbWF0X3N1YikpICU+JQogIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgcmVuYW1lKGdlbmUgPSBuYW1lKSAjJT4lIEdSYW5nZXMoKQoKCiMgc3Vic2V0IGF0YWMgZ3JhbmdlcyAmIGdldCBtaWRkbGUgb2YgZWFjaCBwZWFrCnBvc19hdGFjX2dyYW5nZXMgPC0gYXRhY19ncmFuZ2VzICAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICMgdW5ncm91cCAlPiUKICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICBmaWx0ZXIoaWR4QVRBQyAlaW4lIGNvbG5hbWVzKHAyZ19tYXRfc3ViKSkgJT4lIAogIG11dGF0ZShtaWRkbGUgPSBzdGFydCArIDMwMCkgIyU+JSBHUmFuZ2VzKCkgCgojVE9ETzogRmlsdGVyIGZvciBnZW5lcyEKc3RvcGlmbm90KGxlbmd0aCh1bmlxdWUobGlua3MkaWR4QVRBQykpID09IGRpbShwb3NfYXRhY19ncmFuZ2VzKVtbMV1dKQpzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhSTkEpKSA9PSBkaW0oZ2VuZV9hbm5vKVtbMV1dKQojcDJnX2ZpbHQgPC0gcDJnX29yaWdpbmFsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGZpbHRlcihnZW5lICVpbiUgcm93bmFtZXMocDJnX21hdCkpCgoKICAjIGZpbmQgb3ZlcmxhcHBpbmcgcGVha3MgYW5kIGdlbmUgd2luZG93IGluIGNocm9tb3NvbWUtYXdhcmUgZmFzaGlvbgp0YWRfb3ZlcmxhcHNfZ2VuZXMgPC0gc3VwcHJlc3NXYXJuaW5ncyhmaW5kT3ZlcmxhcHMoZ2VuZV9hbm5vICU+JSBHUmFuZ2VzKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQoKcDEgPC0gdGFkX292ZXJsYXBzX2dlbmVzICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG4pLCBiaW5zID0gMTAwKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgaGlnaGx5IHZhcmlhYmxlIGdlbmVzIHdpdGhpbiBhIHRhZCBib3VuZGFyeSIsCiAgICAgICB4ID0gIm51bWJlciBvZiBnZW5lcy90YWQgYm91bmRhcnkiKQoKdGFkX292ZXJsYXBzX3BlYWtzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKHBvc19hdGFjX2dyYW5nZXMgJT4lIEdSYW5nZXMoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWRfYm91bmRhcmllcykpCgoKcDIgPC0gdGFkX292ZXJsYXBzX3BlYWtzICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgCiAgZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG4pLCBiaW5zID0gMTAwKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgcGVha3Mgd2l0aGluIGEgdGFkIGJvdW5kYXJ5IiwKICAgICAgIHggPSAibnVtYmVyIG9mIHBlYWtzL3RhZCBib3VuZGFyeSIpCgoKY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgbmNvbCA9IDIpCmBgYAoKSG93IG1hbnkgcDJnIGxpbmtzIGFyZSB3aXRoaW4gdGFkIGJvdW5kYXJpZXM/CgpQZWFrLXRvLWdlbmUgbGlua3MgY29uc2lkZXJlZCBpbiBhYm92ZSBjb21wdXRhdGlvbnMKCkFsbCBwZWFrLXRvLWdlbmUgbGlua3MKCmBgYCN7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTV9CnJtKHBlYWtzKQpnYyhyZXNldCA9IFRSVUUpCgpwMmdfcG9zIDwtIHAyZyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBmaWx0ZXIoQ29ycmVsYXRpb24gPiAwKSAlPiUKICB1bml0ZShsaW5rLCBpZHhSTkEsIGlkeEFUQUMsIHNlcCA9ICIlIiwgcmVtb3ZlID0gRkFMU0UpCgpnZW5lX2Fubm9fYWxsIDwtIHJvd0RhdGEoZ2VuZV9leHByKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhSTkEgPSBzZXEobnJvdyguKSkpICU+JSAKICBmaWx0ZXIoaWR4Uk5BICVpbiUgcDJnX3BvcyRpZHhSTkEpICU+JQogIG11dGF0ZShzdHJhbmQgPSBpZmVsc2Uoc3RyYW5kID09IDEsICIrIiwgIi0iKSkgJT4lCiAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgcmVuYW1lKGdlbmUgPSBuYW1lKSAjJT4lIEdSYW5nZXMoKQoKIyBzdWJzZXQgYXRhYyBncmFuZ2VzICYgZ2V0IG1pZGRsZSBvZiBlYWNoIHBlYWsKcG9zX2F0YWNfZ3Jhbmdlc19hbGwgPC0gbWV0YWRhdGEocDJnKVtbMV1dICAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIG11dGF0ZShpZHhBVEFDID0gc2VxKG5yb3coLikpKSAlPiUgCiAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgIyBtdXRhdGUoaWR4ID0gc2VxX2Fsb25nKHNlcW5hbWVzKSkgJT4lIAogICMgdW5ncm91cCAlPiUKICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICBmaWx0ZXIoaWR4QVRBQyAlaW4lIHAyZ19wb3MkaWR4QVRBQykgJT4lIAogIG11dGF0ZShtaWRkbGUgPSBzdGFydCArIDMwMCkgIyU+JSBHUmFuZ2VzKCkgCgoKCiMgY29tYmluZSB0aGUgdGhyZWUgZGF0YWZyYW1lcwpwMmdfam9pbl9hbGwgPC0gbGVmdF9qb2luKHAyZ19wb3MsIGFzLmRhdGEuZnJhbWUocG9zX2F0YWNfZ3Jhbmdlc19hbGwpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4QVRBQyIpCnAyZ19qb2luX2FsbCA8LSBsZWZ0X2pvaW4ocDJnX2pvaW5fYWxsLCBhcy5kYXRhLmZyYW1lKGdlbmVfYW5ub19hbGwpLAogICAgICAgICAgICAgICAgICAgICAgYnkgPSAiaWR4Uk5BIiwgc3VmZml4ID0gYygiLmF0YWMiLCAiLnJuYSIpKQoKCnAyZ19qb2luX2FsbCA8LSBwMmdfam9pbl9hbGwgJT4lIAogIG11dGF0ZShkaXN0YW5jZSA9IGFicyhzdGFydF9jb29yZCAtIG1pZGRsZSkpCgoKCiAgIyBmaW5kIG92ZXJsYXBwaW5nIHBlYWtzIGFuZCBnZW5lIHdpbmRvdyBpbiBjaHJvbW9zb21lLWF3YXJlIGZhc2hpb24KdGFkX292ZXJsYXBzX2dlbmVzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKGdlbmVfYW5ub19hbGwgJT4lIEdSYW5nZXMoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWRfYm91bmRhcmllcykpCgojIGdldCBnZW5lcyB3aGljaCBhcmUgbm90IGZvdW5kIHdpdGhpbiB0d28gVEFEIGJvdW5kYXJpZXMsIGJ1dCBvbmx5IHdpdGhpbiBvbmUKd2l0aGluX2dlbmVzIDwtICh0YWRfb3ZlcmxhcHNfZ2VuZXMgJT4lIAphcy5kYXRhLmZyYW1lKCkgJT4lIApncm91cF9ieShxdWVyeUhpdHMpICU+JQpzdW1tYXJpc2UobiA9IG4oKSkgJT4lIHVuZ3JvdXAoKSAlPiUKZmlsdGVyKG4gPCAyKSkkcXVlcnlIaXRzCgpwcmludChwYXN0ZTAoIk91dCBvZiAiLCBucm93KGdlbmVfYW5ub19hbGwpLCAiIGdlbmVzLCAiLCBsZW5ndGgodW5pcXVlKHF1ZXJ5SGl0cyh0YWRfb3ZlcmxhcHNfZ2VuZXMpKSksICIgZ2VuZXMgYXJlIHdpdGhpbiBUQUQgYm91bmRhcmllcy4gU29tZSBvZiB0aGVzZSBnZW5lcyBldmVuIHNwYW4gYWNyb3NzIFRBRCBib3VkbmFyaWVzLCBuYW1lbHkgIiwgYWJzKGxlbmd0aCh3aXRoaW5fZ2VuZXMpIC0gbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHModGFkX292ZXJsYXBzX2dlbmVzKSkpKSwgIi4iKSkKCiMgV2Ugb25seSBrZWVwIGdlbmVzIHdpdGhpbiBib3VuZGFyaWVzLCBidXQgbm90IGdlbmVzIGNyb3NzaW5nIGJvdW5kYXJpZXMKdGFkX292ZXJsYXBzX2dlbmVzIDwtIHRhZF9vdmVybGFwc19nZW5lcyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZmlsdGVyKHF1ZXJ5SGl0cyAlaW4lIHdpdGhpbl9nZW5lcykgIyU+JSBTNFZlY3RvcnM6OmFzKCkKCiMgZ2V0IHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggdGFkIGJvdW5kYXJpZXMKdGFkX292ZXJsYXBzX3BlYWtzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKHBvc19hdGFjX2dyYW5nZXNfYWxsICU+JSBHUmFuZ2VzKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZF9ib3VuZGFyaWVzKSkKCiMgZmlsdGVyIGZvciBwZWFrcyBvdmVybGFwcGluZyB0YWQgYm91bmRhcmllcyB3aGljaCBhbHNvIGNvbnRhaW4gZ2VuZXMKdGFkX292ZXJsYXBzX3BlYWtzIDwtIHRhZF9vdmVybGFwc19wZWFrcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBmaWx0ZXIoc3ViamVjdEhpdHMgJWluJSB0YWRfb3ZlcmxhcHNfZ2VuZXMkc3ViamVjdEhpdHMpCgojIGNvbWJpbmUgdGFkIGJvdW5kYXJpZXMgd2hpY2ggY29udGFpbiBnZW5lcyBhbmQgcGVha3MKdGFkX2NvbWJpbmUgPC0gbGVmdF9qb2luKHRhZF9vdmVybGFwc19nZW5lcywgdGFkX292ZXJsYXBzX3BlYWtzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvcHkgPSBUUlVFLCBieSA9ICJzdWJqZWN0SGl0cyIsIHN1ZmZpeCA9IGMoIi5nZW5lIiwgIi5wZWFrIikpICU+JQogIHVuaXRlKGxpbmssIHF1ZXJ5SGl0cy5nZW5lLCBxdWVyeUhpdHMucGVhaywgc2VwID0gIiUiLCByZW1vdmUgPSBGQUxTRSkKCgpnZW5lcyA8LSBnZW5lX2Fubm9fYWxsW3RhZF9jb21iaW5lJHF1ZXJ5SGl0cy5nZW5lLCBdICU+JQogIG11dGF0ZSh0YWRfaW5kZXggPSB0YWRfY29tYmluZSRzdWJqZWN0SGl0cykKCnBlYWtfY29sbCA8LSBwb3NfYXRhY19ncmFuZ2VzX2FsbFt0YWRfY29tYmluZSRxdWVyeUhpdHMucGVhaywgXSAlPiUgCiAgbXV0YXRlKHRhZF9pbmRleCA9IHRhZF9jb21iaW5lJHN1YmplY3RIaXRzKQoKZ2VuZV9wZWFrX3RhZF9kZiA8LSBsZWZ0X2pvaW4oZ2VuZXMsIHBlYWtfY29sbCwgYnkgPSAidGFkX2luZGV4Iiwgc3VmZmljID0gYygiLmdlbmUiLCAiLnBlYWsiKSkgJT4lICB1bml0ZShwZWFrX2dlbmVfdGFkLCBnZW5lLCBpZHhBVEFDLCBzZXAgPSAiIyIsIHJlbW92ZSA9IEZBTFNFKQoKIyMjIHNvbWUgcGxvdHMKcDEgPC0gKHRhZF9vdmVybGFwc19wZWFrcyAgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICBncm91cF9ieShzdWJqZWN0SGl0cykgJT4lICMgZ2VuZSByZWdpb24KICAgICAgIHN1bW1hcml6ZShuID0gbigpKSAlPiUgIyBnZXQgbnVtYmVyIG9mIHBlYWtzIG92ZXJsYXBwaW5nIHdpdGggYSBnZW5lIHJlZ2lvbgogICAgICAgZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG4pLCBiaW5zID0gMTAwLCBmaWxsPSIjNjliM2EyIikgKwogICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgcGVha3MgcGVyIHRhZCBib3VuZGFyeSwgcG9zaXRpdmUgcDJnIGxpbmtzIiwKICAgICAgICAgICB4ID0gIm51bWJlciBvZiBwZWFrcyIpKQoKcDIgPC0gKHRhZF9vdmVybGFwc19nZW5lcyAgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JSAjIGdlbmUgcmVnaW9uCiAgICAgc3VtbWFyaXplKG4gPSBuKCkpICU+JSAjIGdldCBudW1iZXIgb2YgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCBhIGdlbmUgcmVnaW9uCiAgICAgZ2dwbG90KCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IG4pLCBiaW5zID0gMTAwLCBmaWxsPSIjNjliM2EyIikgKwogICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGdlbmVzIHBlciB0YWQgYm91bmRhcnksIHBvc2l0aXZlIHAyZyBsaW5rcyIsCiAgICAgICAgIHggPSAibnVtYmVyIG9mIGdlbmVzIikpCgpwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMikpCgoKCnByaW50KHBhc3RlMCgiVGhlIG51bWJlciBvZiBwb3NpdGl2ZSBwZWFrLXRvLWdlbmUgbGlua3MgaXM6ICIsIGxlbmd0aChwMmdfcG9zJGxpbmspKSkKcHJpbnQocGFzdGUwKCAiVGhlIG51bWJlciBvZiBwb3NpdGl2ZSBwZWFrLXRvLWdlbmUgbGlua3Mgd2l0aGluIFRBRCBib3VuZGFyaWVzIGlzOiAiLCBsZW5ndGgodGFkX2NvbWJpbmUkbGluaykpKQoKcHJpbnQocGFzdGUwKCJUaGUgbnVtYmVyIG9mIHBvc2l0aXZlIHBlYWstdG8tZ2VuZSBsaW5rcyBvdXRzaWRlIFRBRCBib3VuZGFyaWVzIGlzOiAiLCBsZW5ndGgocDJnX3BvcyRsaW5rKSAtIGxlbmd0aCh0YWRfY29tYmluZSRsaW5rKSkpCgoKcHJpbnQocGFzdGUwKCJUaGUgcHJvcG9ydGlvbiBvZiBwZWFrLXRvLWdlbmUgbGlua3Mgd2l0aGluIFRBRCBib3VuZGFyaWVzIG91dCBvZiBhbGwgCiAgICAgICAgICAgICBwb3NpdGl2ZSBwZWFrLXRvLWdlbmUgbGlua3MgYWNyb3NzIHRoZSBlbnRpcmUgY2hyb21vc29tZSBpcyAiLAogICAgICAgICAgICAgcm91bmQobGVuZ3RoKHRhZF9jb21iaW5lJGxpbmspIC8gbGVuZ3RoKHAyZ19wb3MkbGluayksIDUpKSkKCgoKI2dncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoeCA9IHAyZ19wb3MkaWR4QVRBQywgeSA9IHAyZ19wb3MkaWR4Uk5BKSkKCgpgYGAKCiMjIERpc3RhbmNlIHZzLiBDb3JyZWxhdGlvbgoKSGVyZSBJIHZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYmV0d2VlbiBwZWFrcyBhbmQgZ2VuZXMKYW5kIHRoZWlyIHJlc3BlY3RpdmUgY29ycmVsYXRpb24gdmFsdWVzIHVzaW5nIGFsbCBwb3NpdGl2ZSBsaW5rcyBvYnRhaW5lZCAKdXNpbmcgQXJjaFIgCgpgYGAje3J9CnAyZ19qb2luX2FsbCAlPiUgIAogIG11dGF0ZShiaW49Y3V0X3dpZHRoKGRpc3RhbmNlLCB3aWR0aD0xMDAwMDAsIGJvdW5kYXJ5PTApKSAlPiUKICBmaWx0ZXIoZGlzdGFuY2UgPCAxMDAwMDAwMCkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBiaW4sIHkgPSBDb3JyZWxhdGlvbiksIGZpbGw9IiM2OWIzYTIiKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCAgPSAyNTAwMDAsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc3RhbmNlIGFuZCBjb3JyZWxhdGlvbiBvZiBwMmcgbGlua3MsIDEwMGtiIGJpbnMiLAogICAgICAgeCA9ICJEaXN0YW5jZSBiZXR3ZWVuIHBlYWtzIGFuZCBnZW5lcyB3aXRoaW4gMjUwa2IiLCB5ID0gIkNvcnJlbGF0aW9uIikgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTh9Cgpjb2xQYWxldHRlX2NlbGx0eXBlcyA9IGMoJyM1MzJDOEEnLAogJyNjMTlmNzAnLAogJyNmOWRlY2YnLAogJyNjOWE5OTcnLAogJyNCNTFEOEQnLAogJyMzRjg0QUEnLAogJyM5ZTY3NjInLAogJyMzNTRFMjMnLAogJyNGMzk3QzAnLAogJyNmZjg5MWMnLAogJyM2MzU1NDcnLAogJyNDNzIyMjgnLAogJyNmNzkwODMnLAogJyNFRjRFMjInLAogJyM5ODk4OTgnLAogJyM3RjY4NzQnLAogJyM4ODcwYWQnLAogJyM2NDdhNGYnLAogJyNFRjVBOUQnLAogJyNGQkJFOTInLAogJyMxMzk5OTInLAogJyNjYzc4MTgnLAogJyNERkNERTQnLAogJyM4RUM3OTInLAogJyNDNTk0QkYnLAogJyNDM0MzODgnLAogJyMwRjRBOUMnLAogJyNGQUNCMTInLAogJyM4REI1Q0UnLAogJyMxQTFBMUEnLAogJyNDOUVCRkInLAogJyNEQUJFOTknLAogJyM2NUE4M0UnLAogJyMwMDU1NzknLAogJyNDREUwODgnLAogJyNmN2Y3OWUnLAogJyNGNkJGQ0InKQoKdGFkX2JvdW5kYXJpZXMgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZ3JvdXBfYnkoc2VxbmFtZXMpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIHVuZ3JvdXAoKSAlPiUgIAogIGdncGxvdCgpICsgZ2VvbV9jb2woYWVzKHggPSBzZXFuYW1lcywgeSA9IG4sIGZpbGwgPSBzZXFuYW1lcyksIGFscGhhID0gLjcsICkgKyMsIHBvc2l0aW9uID0gImRvZGdlIikKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xQYWxldHRlX2NlbGx0eXBlcykgKwogIGxhYnMoeSA9ICJudW1iZXIgb2YgdGFkIGJvdW5kYXJpZXMiKQoKYGBgCgoKVE9ETzogU2hvdWxkIEkgYWxzbyByZW1vdmUgcGVha3Mgd2hpY2ggYXJlIGFjcm9zcyBUQUQgYm91bmRhcmllcz8KCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTB9CiMgQXMgaW5wdXQgZm9yIHRoaXMgZnVuY3Rpb24gaXQgaXMgYmVzdCB0byB1c2Ugb25seSB0aGUgbW9zdCBoaWdobHkgdmFyaWFibGUgZ2VuZXMKdGFkX2JvdW5kYXJpZXNfcDJnX3Njb3JlcyA8LSBmdW5jdGlvbihwMmdfbWF0X3N1YiwgcGVha19tYXQsIGxpbmtzLCBwMmdfb3JpZ2luYWwsIGdlbmVfZXhwciwgdGFkX2JvdW5kYXJpZXMpewogIGF0YWNfZ3JhbmdlcyA8LSBtZXRhZGF0YShwMmdfb3JpZ2luYWwpW1sxXV0KICAjcm5hX2dyYW5nZXMgPC0gbWV0YWRhdGEocDJnX29yaWdpbmFsKVtbMl1dCiAgZ2VuZV9hbm5vIDwtIHJvd0RhdGEoZ2VuZV9leHByKQogIAogICMgY3JlYXRlIGdlbmUgYW5ub3RhdGlvbnMgd2l0aCBzdGFydCBjb29yZGluYXRlIG9mIGVhY2ggZ2VuZQogICMgc3Vic2V0IHRvIGNvbnRhaW4gb25seSBnZW5lcyB3aGljaCBhcmUgaW5jbHVkZWQgaW4gb3VyIHBlYWsyZ2VuZSBtYXRyaXgKICBnZW5lX2Fubm8gPC0gZ2VuZV9hbm5vICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBtdXRhdGUoaWR4Uk5BID0gc2VxKG5yb3coLikpKSAlPiUgCiAgICBmaWx0ZXIobmFtZSAlaW4lIHJvd25hbWVzKHAyZ19tYXRfc3ViKSkgJT4lCiAgICBtdXRhdGUoc3RyYW5kID0gaWZlbHNlKHN0cmFuZCA9PSAxLCAiKyIsICItIikpICU+JQogICAgbXV0YXRlKHN0YXJ0X2Nvb3JkID0gaWZlbHNlKHN0cmFuZCA9PSAiKyIsIHN0YXJ0LCBlbmQpKSAlPiUgCiAgICByZW5hbWUoZ2VuZSA9IG5hbWUpICMlPiUgR1JhbmdlcygpCgoKICAjIHN1YnNldCBhdGFjIGdyYW5nZXMgJiBnZXQgbWlkZGxlIG9mIGVhY2ggcGVhawogIHBvc19hdGFjX2dyYW5nZXMgPC0gYXRhY19ncmFuZ2VzICAlPiUgCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBtdXRhdGUoaWR4QVRBQyA9IHNlcShucm93KC4pKSkgJT4lIAogICAgIyBncm91cF9ieShzZXFuYW1lcykgJT4lCiAgICAjIG11dGF0ZShpZHggPSBzZXFfYWxvbmcoc2VxbmFtZXMpKSAlPiUgCiAgICAjIHVuZ3JvdXAgJT4lCiAgICAjdGlkeXI6OnVuaXRlKGNocl9pZHgsIHNlcW5hbWVzLCBpZHgsIHJlbW92ZSA9IEZBTFNFLCBzZXAgPSAiXyIpICU+JSAKICAgIGZpbHRlcihpZHhBVEFDICVpbiUgY29sbmFtZXMocDJnX21hdF9zdWIpKSAlPiUgCiAgICBtdXRhdGUobWlkZGxlID0gc3RhcnQgKyAzMDApICMlPiUgR1JhbmdlcygpIAogIAogICNUT0RPOiBGaWx0ZXIgZm9yIGdlbmVzIQogIHN0b3BpZm5vdChsZW5ndGgodW5pcXVlKGxpbmtzJGlkeEFUQUMpKSA9PSBkaW0ocG9zX2F0YWNfZ3JhbmdlcylbWzFdXSkKICBzdG9waWZub3QobGVuZ3RoKHVuaXF1ZShsaW5rcyRpZHhSTkEpKSA9PSBkaW0oZ2VuZV9hbm5vKVtbMV1dKQogICNwMmdfZmlsdCA8LSBwMmdfb3JpZ2luYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKGdlbmUgJWluJSByb3duYW1lcyhwMmdfbWF0KSkKICAKICAKICAgICMgZmluZCBvdmVybGFwcGluZyBwZWFrcyBhbmQgZ2VuZSB3aW5kb3cgaW4gY2hyb21vc29tZS1hd2FyZSBmYXNoaW9uCiAgdGFkX292ZXJsYXBzX2dlbmVzIDwtIHN1cHByZXNzV2FybmluZ3MoZmluZE92ZXJsYXBzKGdlbmVfYW5ubyAlPiUgR1JhbmdlcygpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQogIAogICMgZ2V0IGdlbmVzIHdoaWNoIGFyZSBub3QgZm91bmQgd2l0aGluIHR3byBUQUQgYm91bmRhcmllcywgYnV0IG9ubHkgd2l0aGluIG9uZQogIHdpdGhpbl9nZW5lcyA8LSAodGFkX292ZXJsYXBzX2dlbmVzICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGdyb3VwX2J5KHF1ZXJ5SGl0cykgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKG4gPCAyKSkkcXVlcnlIaXRzCgogIHByaW50KHBhc3RlMCgiT3V0IG9mICIsIG5yb3coZ2VuZV9hbm5vKSwgIiBnZW5lcywgIiwgbGVuZ3RoKHVuaXF1ZShxdWVyeUhpdHModGFkX292ZXJsYXBzX2dlbmVzKSkpLCAiIGdlbmVzIGFyZSB3aXRoaW4gVEFEIGJvdW5kYXJpZXMuIFNvbWUgb2YgdGhlc2UgZ2VuZXMgZXZlbiBzcGFuIGFjcm9zcyBUQUQgYm91ZG5hcmllcywgbmFtZWx5ICIsIGxlbmd0aCh3aXRoaW5fZ2VuZXMpLCAiLiIpKQogIAogICMgV2Ugb25seSBrZWVwIGdlbmVzIHdpdGhpbiBib3VuZGFyaWVzLCBidXQgbm90IGdlbmVzIGNyb3NzaW5nIGJvdW5kYXJpZXMKICB0YWRfb3ZlcmxhcHNfZ2VuZXMgPC0gdGFkX292ZXJsYXBzX2dlbmVzICU+JSBhcy5kYXRhLmZyYW1lICU+JSAKICAgIGZpbHRlcihxdWVyeUhpdHMgJWluJSB3aXRoaW5fZ2VuZXMpICMlPiUgUzRWZWN0b3JzOjphcygpCiAgCiAgIyBnZXQgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCB0YWQgYm91bmRhcmllcwogIHRhZF9vdmVybGFwc19wZWFrcyA8LSBzdXBwcmVzc1dhcm5pbmdzKGZpbmRPdmVybGFwcyhwb3NfYXRhY19ncmFuZ2VzICU+JSBHUmFuZ2VzKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQogIAogICMgZmlsdGVyIGZvciBwZWFrcyBvdmVybGFwcGluZyB0YWQgYm91bmRhcmllcyB3aGljaCBhbHNvIGNvbnRhaW4gZ2VuZXMKICB0YWRfb3ZlcmxhcHNfcGVha3MgPC0gdGFkX292ZXJsYXBzX3BlYWtzICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgZmlsdGVyKHN1YmplY3RIaXRzICVpbiUgdGFkX292ZXJsYXBzX2dlbmVzJHN1YmplY3RIaXRzKQogIAogICMgY29tYmluZSB0YWQgYm91bmRhcmllcyB3aGljaCBjb250YWluIGdlbmVzIGFuZCBwZWFrcwogIHRhZF9jb21iaW5lIDwtIGxlZnRfam9pbih0YWRfb3ZlcmxhcHNfZ2VuZXMsIHRhZF9vdmVybGFwc19wZWFrcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcHkgPSBUUlVFLCBieSA9ICJzdWJqZWN0SGl0cyIsIHN1ZmZpeCA9IGMoIi5nZW5lIiwgIi5wZWFrIikpCiAgCiAgCiAgZ2VuZXMgPC0gZ2VuZV9hbm5vW3RhZF9jb21iaW5lJHF1ZXJ5SGl0cy5nZW5lLCBdICU+JQogICAgbXV0YXRlKHRhZF9pbmRleCA9IHRhZF9jb21iaW5lJHN1YmplY3RIaXRzKQogIAogIHBlYWtfY29sbCA8LSBwb3NfYXRhY19ncmFuZ2VzW3RhZF9jb21iaW5lJHF1ZXJ5SGl0cy5wZWFrLCBdICU+JSAKICAgIG11dGF0ZSh0YWRfaW5kZXggPSB0YWRfY29tYmluZSRzdWJqZWN0SGl0cykKICAKICBnZW5lX3BlYWtfdGFkX2RmIDwtIGxlZnRfam9pbihnZW5lcywgcGVha19jb2xsLCBieSA9ICJ0YWRfaW5kZXgiLCBzdWZmaWMgPSBjKCIuZ2VuZSIsICIucGVhayIpKSAlPiUgIHVuaXRlKHBlYWtfZ2VuZV90YWQsIGdlbmUsIGlkeEFUQUMsIHNlcCA9ICIjIiwgcmVtb3ZlID0gRkFMU0UpCgoKICAKICAjIyMgc29tZSBwbG90cwogIHAxIDwtICh0YWRfb3ZlcmxhcHNfcGVha3MgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICBncm91cF9ieShzdWJqZWN0SGl0cykgJT4lICMgZ2VuZSByZWdpb24KICAgICAgICAgc3VtbWFyaXplKG4gPSBuKCkpICU+JSAjIGdldCBudW1iZXIgb2YgcGVha3Mgb3ZlcmxhcHBpbmcgd2l0aCBhIGdlbmUgcmVnaW9uCiAgICAgICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICAgICAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgcGVha3MgcGVyIHRhZCBib3VuZGFyeSIsCiAgICAgICAgICAgICB4ID0gIm51bWJlciBvZiBwZWFrcyIpKQogIAogIHAyIDwtICh0YWRfb3ZlcmxhcHNfZ2VuZXMgICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgZ3JvdXBfYnkoc3ViamVjdEhpdHMpICU+JSAjIGdlbmUgcmVnaW9uCiAgICAgICBzdW1tYXJpemUobiA9IG4oKSkgJT4lICMgZ2V0IG51bWJlciBvZiBwZWFrcyBvdmVybGFwcGluZyB3aXRoIGEgZ2VuZSByZWdpb24KICAgICAgIGdncGxvdCgpICsgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBuKSwgYmlucyA9IDEwMCwgZmlsbD0iIzY5YjNhMiIpICsKICAgICAgIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGh2ZyBnZW5lcyBwZXIgdGFkIGJvdW5kYXJ5IiwKICAgICAgICAgICB4ID0gIm51bWJlciBvZiBnZW5lcyIpKQogIAogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAyKSkKICAKICAKICAjIGNvbWJpbmUgdGhlIGFubm90YXRpb24gZGF0YWZyYW1lIHdpdGggdGhlIHAyZyBsaW5rcyBkYXRhZnJhbWUKICBwMmdfam9pbiA8LSBsZWZ0X2pvaW4obGlua3MsIGFzLmRhdGEuZnJhbWUocG9zX2F0YWNfZ3JhbmdlcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImlkeEFUQUMiKQogIHAyZ19qb2luIDwtIGxlZnRfam9pbihwMmdfam9pbiwgYXMuZGF0YS5mcmFtZShnZW5lX2Fubm8pLAogICAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhSTkEiLCBzdWZmaXggPSBjKCIuYXRhYyIsICIucm5hIikpCgogICMgY29tcHV0ZSBkaXN0YW5jZSAKICBwMmdfam9pbiA8LSBwMmdfam9pbiAlPiUgCiAgICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoc3RhcnRfY29vcmQgLSBtaWRkbGUpKQogIAogICMgZmlsdGVyIGZvciB0aGUgcDJnIGxpbmtzIHdpdGhpbiB0YWQgYm91bmRhcmllcwogIGNvcnJfdGFkX2JvdW5kYXJ5IDwtIHAyZ19qb2luICU+JSAKICAgIHVuaXRlKHBlYWtfZ2VuZV90YWQsIGdlbmUsIGlkeEFUQUMsIHNlcCA9ICIjIiwgcmVtb3ZlID0gRkFMU0UpICU+JSAKICAgIGZpbHRlcihwZWFrX2dlbmVfdGFkICVpbiUgZ2VuZV9wZWFrX3RhZF9kZiRwZWFrX2dlbmVfdGFkKQoKICAjIyMgUExPVFMKICAKICBwMSA8LSBjb3JyX3RhZF9ib3VuZGFyeSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IENvcnJlbGF0aW9uKSwgYmlucyA9IDIwMCwgZmlsbCA9ICIjNjliM2EyIikgKwogICAgbGFicyh0aXRsZSA9ICJDb3JyZWxhdGlvbiB2YWx1ZXMgb2YgcGVhay10by1nZW5lIGxpbmtzIGZvdW5kIHdpdGhpbiB0YWQgYm91bmRhcmllcyIpCiAgCiAgcDIgPC0gY29ycl90YWRfYm91bmRhcnkgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBkaXN0YW5jZSksIGJpbnMgPSAyMDAsIGZpbGwgPSAiIzY5YjNhMiIpICsKICAgIGxhYnModGl0bGUgPSAiRGlzdGFuY2UgYmV0d2VlbiBwZWFrcyBhbmQgVFNTIHdpdGhpbiB0YWQgYm91bmRhcnkiKQogIAogIHAzIDwtIGNvcnJfdGFkX2JvdW5kYXJ5ICU+JSAKICAgIG11dGF0ZShiaW4gPSBjdXRfd2lkdGgoZGlzdGFuY2UsIHdpZHRoPTEwMDAwMCwgYm91bmRhcnk9MCkpICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGJpbiwgeSA9IENvcnJlbGF0aW9uKSwgZmlsbCA9ICIjNjliM2EyIikgKwogICAgbGFicyh0aXRsZSA9ICJEaXN0YW5jZSBhbmQgQ29ycmVsYXRpb24gd2l0aGluIHRhZCBib3VuZGFyeSwgMTAwa2IgYmlucyIsCiAgICAgICAgIHggPSAiRGlzdGFuY2UgKDEwMGtiIGJpbnMpIikgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpIAoKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBwMywgbmNvbCA9IDEpKQogIAoKCiAgCiAgIyMjIyBQTE9UCiAgcDIgPC0gY29ycl90YWRfYm91bmRhcnkgJT4lIGdncGxvdCgpICsKICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZGlzdGFuY2UpLCBiaW5zID0gNTAwKSArIAogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGxhYnModGl0bGUgPSAiUmVsYXRpdmUgZGlzdGFuY2Ugb2YgcGVha3MgdG8gVFNTIHdpdGhpbiB0YWQgYm91bmRhcmllcyIsCiAgICAgICAgIHggPSAiUmVsYXRpdmUgZGlzdGFuY2UgdG8gVFNTIiwgeSA9ICJsb2cxMChjb3VudCkiKSArIAogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygxMDAwMDAsIC0xMDAwMDApLCBjb2xvciA9ICJyZWQiKQogIAogIHByaW50KHAyKQogICNjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMSkKICAKICAKICAKICBwMmdfbGlua3NfdGFkIDwtIE1hdHJpeDo6c3BhcnNlTWF0cml4KAogICAgICBpID0gY29ycl90YWRfYm91bmRhcnkkaWR4Uk5BLCAKICAgICAgaiA9IGNvcnJfdGFkX2JvdW5kYXJ5JGlkeEFUQUMsIAogICAgICB4ID0gY29ycl90YWRfYm91bmRhcnkkQ29ycmVsYXRpb24sIAogICAgICBkaW1zID0gYyhucm93KGV4cHJfbWF0KSwgbnJvdyhwZWFrX21hdCkpLAogICAgICBkaW1uYW1lcyA9IGxpc3Qocm93bmFtZXMoZXhwcl9tYXQpLHJvd25hbWVzKHBlYWtfbWF0KSkKICAgICkKICAKICAKICBwcmludChwYXN0ZTAoIlRoZSBtYXhpbXVtIHZhbHVlIGlzOiAiLCBtYXgocDJnX2xpbmtzX3RhZCksICIsIHRoZSBtaW51bSB2YWx1ZSBpczogIiwgbWluKHAyZ19saW5rc190YWQpICkpCiAgCiAgCiAgCiAgcDJnX2xpbmtzX3RhZCA8LSBwMmdfbGlua3NfdGFkW3Jvd1N1bXMocDJnX2xpbmtzX3RhZCkgIT0gMCwgXQogIHAyZ19saW5rc190YWQgPC0gcDJnX2xpbmtzX3RhZFssIGNvbFN1bXMocDJnX2xpbmtzX3RhZCkgIT0gMF0KICAKICBwcmludChwYXN0ZTAoIkFmdGVyIHJlbW92aW5nIGFueSByb3dzIGFuZCBjb2x1bXNuIHdoaWNoIGRvIG5vdCBjb250YWluIGFueSBsaW5rcyB3ZSBhcmUgbGVmdCB3aXRoICIsIG5yb3cocDJnX2xpbmtzX3RhZCksICIgZ2VuZXMgYW5kICIsIG5jb2wocDJnX2xpbmtzX3RhZCksICIgcGVha3MuIikpCiAgCiAgCiAgIyBDb21wdXRlIGdlbmUgYWN0aXZpdHkgc2NvcmVzCiAgdGFkX3Njb3JlcyA8LSBnZW5lX2FjdGl2aXR5X3Njb3JlcyhwZWFrX21hdF9zdWJbY29sbmFtZXMocDJnX2xpbmtzX3RhZCksIF0sIHAyZ19saW5rc190YWQpCiAgCiAgcmV0dXJuKHRhZF9zY29yZXMpIAp9CmdjKHJlc2V0ID0gVFJVRSkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0KdGFkX3Njb3JlcyA8LSB0YWRfYm91bmRhcmllc19wMmdfc2NvcmVzKHAyZ19tYXRfc3ViID0gcDJnX21hdF9zdWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZWFrX21hdCA9IHBlYWtfbWF0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlua3MgPSBsaW5rcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwMmdfb3JpZ2luYWwgPSBwMmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9leHByID0gZ2VuZV9leHByLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMgPSB0YWRfYm91bmRhcmllcykKCmdjKHJlc2V0ID0gVFJVRSkKYGBgCgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9CmdlbmVfd2luZG93X2FnZyA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKHRhZF9zY29yZXMsIHNlYWNlbGxzKQpnZW5lX3dpbmRvd19jb3JyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHNlYWNlbGxfcm5hX2FnZywgZ2VuZV93aW5kb3dfYWdnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiR2VuZSB3aW5kb3cgYXJvdW5kIFRTUyIpCgpnZW5lX3dpbmRvd19jb3JyW1syXV0KCgpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IHNlYWNlbGxfY29ycl9hcmNocltbMV1dW25hbWVzKGdlbmVfd2luZG93X2NvcnJbWzFdXSldLCAKICAgICAgICAgICAgICAgICB4ID1nZW5lX3dpbmRvd19jb3JyW1sxXV0pKSAgKwogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHkgPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gZ2VuZV93aW5kb3dfY29ycltbMV1dKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSBzZWFjZWxsX2NvcnJfYXJjaHJbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwgCiAgICAgICAgICAgICAgICB5ID0gc2VhY2VsbF9jb3JyX2FyY2hyW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sIAogICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBwMmcgYWN0aXZpdHkgc2NvcmVzLCB0YWQgYm91bmRhcnkiLAogICAgICAgIHkgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBnZW5lIGV4cHJlc3Npb24gYW5kIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIiwgCiAgICAgICB0aXRsZSA9ICJQZWFrLXRvLWdlbmUgbGlua3Mgd2l0aGluIHRhZCBib3VuZGFyaWVzIikKCmBgYApgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0KZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBzZWFjZWxsX2NvcnJfcDJnW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sIAogICAgICAgICAgICAgICAgIHggPWdlbmVfd2luZG93X2NvcnJbWzFdXSkpICArCiAgZ2VvbV9kZW5zaXR5XzJkX2ZpbGxlZChhZXMoeSA9IHNlYWNlbGxfY29ycl9wMmdbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gZ2VuZV93aW5kb3dfY29ycltbMV1dKSwgYWxwaGEgPSAwLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSBzZWFjZWxsX2NvcnJfcDJnW1sxXV1bbmFtZXMoZ2VuZV93aW5kb3dfY29ycltbMV1dKV0sIAogICAgICAgICAgICAgICAgeSA9IHNlYWNlbGxfY29ycl9wMmdbWzFdXVtuYW1lcyhnZW5lX3dpbmRvd19jb3JyW1sxXV0pXSwgCiAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgICsKICBsYWJzKHggPSAiQ29ycmVsYXRpb24sIHRhZCBib3VuZGFyaWVzIiwKICAgICAgICB5ID0gIkNvcnJlbGF0aW9uLCBhbGwgcDJnIGxpbmtzICIsIAogICAgICAgdGl0bGUgPSAiUGVhay10by1nZW5lIGxpbmtzIHdpdGhpbiB0YWQgYm91bmRhcmllcyB2cy4gYWxsIGxpbmtzIikKYGBgCgoKCgoKCiMgQWRhcHRlZCBBcmNociBHZW5lIEFjdGl2aXR5IFNjb3JlIGZ1bmN0aW9uCgpBcmNoUiBwcm92aWRlcyBhIGZ1bmN0aW9uIHRvIGNvbXB1dGUgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYmFzZWQgb24gYWNjZXNzaWJpbGl0eSAKaW4gdGhlIHJlZ2lvbnMgYXJvdW5kIHRoZSBnZW5lLiBGb3IgdGhpcyBhIHRpbGUgbWF0cml4IGlzIHVzZWQuIFRoaXMgdGlsZSBtYXRyaXggCmlzIGEgbWF0cml4IHdoZXJlIHRoZSBnZW5vbWUgaXMgZGl2aWRlZCBpbnRvIGJpbnMgb2YgNTAwYnAuIElmIHRoZXJlIGlzIGEKVG41IGluc2VydGlvbiBpbiBhIGJpbiB0aGUgZW50cnkgd2lsbCBiZSAxLCBpZiB0aGVyZSBpcyBubyBpbnNlcnRpb24gdGhlIGVudHJ5CndpbGwgYmUgMC4gSW1wb3J0YW50bHksIHRoZXkgY29tcGFyZWQgdGhlaXIgZnVuY3Rpb24gdG8gNTIgb3RoZXIgZnVuY3Rpb25zCmFuZCBmb3VuZCB0aGVpciBvd24gZnVuY3Rpb24gdG8gYmUgdGhlIGJlc3QgcGVyZm9ybWluZy4gCgpIZXJlIEkgdHJpZWQgdG8gYmV0dGVyIHVuZGVyc3RhbmQgaG93IHRoaXMgZnVuY3Rpb24gd29ya3MgYW5kIGNoYW5nZWQgdGhlIHNvdXJjZSAKY29kZSBvZiB0aGUgQXJjaFIgZnVuY3Rpb24gdG8gYWxzbyB0YWtlIHBlYWsgbWF0cml4IGFzIGlucHV0IGFuZCBjb21wdXRlIHRoZSBnZW5lIGFjdGl2aXR5IApiYXNlZCBvbiBwZWFrcywgcmF0aGVyIHRoYW4gYmFzZWQgb24gdGlsZXMuIEFkZGl0aW9uYWxseSwgSSBhZGFwdGVkIHRoZSBmdW5jaXRvbiAKaW4gYSB3YXkgc3VjaCB0aGF0IGl0IHRha2VzIHRhZCBib3VuZGFyaWVzIGFzIGlucHV0IGFuZCB1c2VzIGFsbCBwZWFrcyB3aGljaCBhcmUgCndpdGhpbiB0aGUgc2FtZSB0YWQgYm91bmRhcnkgYXMgYSBnZW5lIHRvIGNvbXB1dGUgdGhlIGFjdGl2aXR5IHNjb3Jlcy4gCgpUaGVyZSBhcmUgdHdvIGRpZmZlcmVudCBvcHRpb25zIGZvciBjb21wdXRpbmcgZ2VuZSBhY3Rpdml0eSBzY29yZXMgaW4gQXJjaFIuIEZpcnN0LAp3ZSBjYW4gdXNlIHRoZSBUU1MgYW5kIGNyZWF0ZSBhIGdlbmUgd2luZG93IGFyb3VuZCBpdCAoKy8tIDEwMGtwIG9mIFRTUykuIEFsbCAKaW5zZXJ0aW9ucyBmb3VuZCB3aXRoaW4gdGlsZXMgd2l0aGluIHRoaXMgZ2VuZSB3aW5kb3cgd2lsbCBiZSBhY2N1bXVsYXRlZCBmb3IgdGhlCmdlbmUgYWN0aXZpdHkgc2NvcmVzLiBJZiB3ZSBzZXQgdGhlIG9wdGlvbiAndXNlR2VuZUJvdW5kYXJpZXM9VFJVRScgdGhlbiB3ZSB3aWxsIAptYWtlIHN1cmUgdGhhdCBubyByZWdpb25zIG92ZXJsYXAgYmV0d2VlbiBhbnkgdHdvIGdlbmVzLiBJZiB0aGUgZ2VuZSB3aW5kb3cgb2YgCm9uZSBnZW5lIG92ZXJsYXBzIHdpdGggdGhlIGdlbmUgd2luZG93IG9mIGFub3RoZXIgZ2VuZSwgdGhvc2UgdGlsZXMgYXJlIG5vdCAKY29uc2lkZXJlZCBhbnltb3JlLiBUaGUgZGlzYWR2YW50YWdlIG9mIHRoaXMgYXBwcm9hYyBpcyB0aGF0IGdlbmVzIGNhbiBiZSB2ZXJ5IApsYXJnZSAoPjEwMGJwKSwgbWVhbmluZyB0aGF0IGluIHNvbWUgY2FzZXMgdGhlIDEwMGtwIGV4dGVuc2lvbiBkb3duc3RyZWFtIG9mIHRoZQpUU1Mgd291bGQgbm90IGV2ZW4gY29udGFpbiB0aGUgZW50aXJlIGdlbmUgYm9keS4gCgpTZWNvbmQsIHdlIGNhbiB1c2UgdGhlIGVudGlyZSBnZW5lIGJvZHkgYW5kIGV4dGVuZCB0aGUgZ2VuZSB3aW5kb3cgYmV5b25kIHRoZSBzdGFydAphbmQgZW5kIGNvb3JkaW5hdGVzIG9mIHRoZSBnZW5lIGJvZHkuIEltcG9ydGFudGx5LCB0aGUgZ2VuZSBib2R5IGlzIGV4dGVuZGVkIDVrYgp1cHN0cmVhbSBvZiB0aGUgVFNTLCB0byBhbHNvIGluY2x1ZGUgdGhlIHByb21vdGVyIHJlZ2lvbi4gVXNpbmcgdGhlIGVudGlyZSBnZW5lIApib2R5IGluc3RlYWQgb2Ygb25seSB0aGUgVFNTIGNhbiBiZSBhY2hpZXZlZCBieSBzZXR0aW5nICd1c2VUU1M9RkFMU0UnLiBJbiB0aGlzIAphcHByb2FjaCB0aGUgZ2VuZSB3aW5kb3cgaXMgY3JlYXRlZCBieSBleHRlbmRpbmcgLTEwMGtiIHVwc3RyZWFtIG9mIHRoZSBUU1MgLTVrYgphbmQgKzEwMGtiIGRvd25zdHJlYW0gb2YgdGhlIGdlbmUgZW5kIGNvb3JkaW5hdGUuIFRoaXMgd2F5LCB0aGUgZW50aXJlIGdlbmUgYm9keSAKd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgZ2VuZSB3aW5kb3cuIEFuIHVud2FudGVkIGNvbnNlcXVlbmNlIG9mIHRoaXMgbWlnaHQgYmUKdGhhdCB2ZXJ5IGxhcmdlIGdlbmVzIGNvdWxkIGJpYXMgdGhlIGdlbmUgYWN0aXZpdHkgc2NvcmVzLiBUaGVyZWZvcmUgQXJjaFIgCmludHJvZHVjZXMgYSB3ZWlnaHQgZm9yIHRoZSBpbnZlcnNlIG9mIHRoZSBnZW5lIGJvZHkgc2l6ZSBhY2NvcmRpbmcgdG86CgokdyA9IFxmcmFjezF9e2dlbmUgc2l6ZX0kIHdpdGggJHckIGJlaW5nIHRoZSBpbnZlcnNlIG9mIHRoZSBnZW5lIHNpemUuCiQKCmdlbmVSZWdpb25zJGdlbmVXZWlnaHQgPC0gMSArIG0gKiAoZ2VuZVNjYWxlRmFjdG9yIC0gMSkgLyAobWF4KG0pIC0gbWluKG0pKSQKCkFkZGl0aW9uYWxseSwgQXJjaFIgdXNlcyBhIGRpc3RhbmNlIHdlaWdodC4gRmFydGhlciBhd2F5IHRpbGVzL3BlYWtzIGFyZSBsZXNzIGxpa2VseSB0byAKaW50ZXJhY3Qgd2l0aCBhIFRTUyB0aGFuIGNsb3NlciB0aWxlcy9wZWFrcy4gSWYgdGhlIGZpcnN0IGFwcHJvYWNoLCB1c2luZyBvbmx5IHRoZQpUU1MsIHRoZSBkaXN0YW5jZSB3ZWlnaHRzIGFyZSBjb21wdXRlZCBhcyBmb2xsb3dzOgoKJHdlaWdodCA9IGVeey0oYWJzKGRpc3RUU1MvNTAwMCkpfSQgd2l0aCAkZGlzdFRTUyQgYmVpbmcgdGhlIGRpc3RhbmNlIGZyb20gdGhlClRTUy4gVGhpcyB3YXkgdGhlIHdlaWdodHMgZGVjYXkgZXhwb25lbnRpYWxseSB3aXRoIGRpc3RhbmNlLiBUaGUgY29uc3RhbnQgdmFsdWUKb2YgJDUwMDAkIGlzIGEgcGFyYW1ldGVyIHdoaWNoIGNvdWxkIGJlIG9wdGltaXplZCBmb3IgZGlmZmVyZW50IGdlbmVzIG9yIGRhdGFzZXRzLCAKYnV0IGhlcmUgd2Ugd2lsbCBrZWVwIGl0IGNvbnN0YW50LiAKCkluIGNhc2UgdGhlIGVudGlyZSBnZW5lIGJvZHkgaXMgdXNlZCwgdGhlIGRpc3RhbmNlIHdlaWdodHMgYXJlIGtlcHQgY29uc3RhbnQgCmZvciBhbGwgdGlsZXMvcGVha3Mgd2l0aGluIHRoZSBnZW5lIGJvZHkgYW5kIG9ubHkgZGVjYXkgYmV5b25kIHRoZSBnZW5lIGJvZHkuCgokd2VpZ2h0ID0gXGJlZ2lue2Nhc2VzfSBpZiAoLTVrYiBmcm9tIFRTUywgVFRTKTogMSArIGVeey0xfSBcXCBlbHNlOiBlXnstYWJzKGRpc3RHQi81MDAwKSArIGVeey0xfX0gXGVuZHtjYXNlc30kCgoKCgojIyBBcmNoUiBHZW5lIEFjdGl2aXR5IFNjb3JlcyB1c2luZyBUQUQgYm91bmRhcmllcwoKSW5zdGVhZCBvZiB1c2luZyBhICsvLTEwMGtiIHdpbmRvdyBhcm91bmQgdGhlIGdlbmUgYm9keSwgaW4gdGhlIGFkYXB0ZWQgCmZ1bmN0aW9uIGFsbCBwZWFrcyB3aGljaCBhcmUgd2l0aGluIHRoZSBzYW1lIFRBRCBib3VuZGFyeSBhcyB0aGUgZ2VuZSBvZiBpbnRlcmVzdAphcmUgY29uc2lkZXJlZCBmb3IgdGhlIGFjdGl2aXR5IHNjb3JlIG9mIHRoYXQgZ2VuZS4gVGhlIGRpc3RhbmNlIHdlaWdodCB3aXRoIApjID0gNTAwMCBpcyBrZXB0IHRoZSBzYW1lIGFzIGZvciB0aGUgZGVmYXVsdCBBcmNoUiBmdW5jdGlvbi4gQXMgY2FuIGJlIHNlZW4gYmVsb3csCmV4dGVuZGluZyB0aGUgZ2VuZSB3aW5kb3cgdG8gVEFEIGJvdW5kYXJpZXMgeWllbGRzIHZlcnkgc2ltaWxhciByZXN1bHRzIGNvbXBhcmVkCnRvIHRoZSBkZWZhdWx0IEFyY2hSIGZ1bmN0aW9uLiAKCmBgYCN7cn0KcHJvaiA8LSBsb2FkQXJjaFJQcm9qZWN0KCIxMl9Db3B5MS8iKQoKIyBwcm9qIDwtIGFkZFRBREdlbmVTY29yZU1hdHJpeCgKIyAgIHByb2osCiMgICBnZW5lcyA9IGdldEdlbmVzKHByb2opLAojICAgcGVha3MgPSBnZXRQZWFrU2V0KHByb2opLAojICAgdGFkQm91bmRhcmllcyA9IHRhZF9ib3VuZGFyaWVzLAojICAgZ2VuZU1vZGVsID0gImV4cCgtYWJzKHgpLzUwMDApICsgZXhwKC0xKSIsCiMgICBtYXRyaXhOYW1lID0gIkdlbmVTY29yZU1hdHJpeCIsCiMgICBleHRlbmRVcHN0cmVhbSA9IGMoMTAwMCwgMTAwMDAwKSwKIyAgIGV4dGVuZERvd25zdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiMgICBnZW5lVXBzdHJlYW0gPSA1MDAwLCAjTmV3IFBhcmFtCiMgICAjZ2VuZURvd25zdHJlYW0gPSAwLCAjTmV3IFBhcmFtCiMgICB1c2VHZW5lQm91bmRhcmllcyA9IEZBTFNFLAojICAgdXNlVFNTID0gRkFMU0UsICNOZXcgUGFyYW0KIyAgIGV4dGVuZFRTUyA9IEZBTFNFLAojICAgdGlsZVNpemUgPSA1MDAsCiMgICBjZWlsaW5nID0gNCwKIyAgIGdlbmVTY2FsZUZhY3RvciA9IDUsICNOZXcgUGFyYW0KIyAgIHNjYWxlVG8gPSAxMDAwMCwKIyAgIGV4Y2x1ZGVDaHIgPSBjKCJjaHJZIiwgImNoclgiLCAiY2hyTSIpLAojICAgYmxhY2tsaXN0ID0gZ2V0QmxhY2tsaXN0KHByb2opLAojICAgdGhyZWFkcyA9IDEsCiMgICBwYXJhbGxlbFBhcmFtID0gTlVMTCwKIyAgIHN1YlRocmVhZGluZyA9IFRSVUUsCiMgICBmb3JjZSA9IFRSVUUsCiMgICBsb2dGaWxlID0gY3JlYXRlTG9nRmlsZSgiLmFkZFRBREdlbmVTY29yZU1hdCIpKQoKc2NvcmVzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIHVzZU1hdHJpeCA9ICJHZW5lU2NvcmVNYXRyaXgiKQpzY29yZV9tYXQgPC0gYXNzYXlzKHNjb3JlcylbWzFdXQpyb3duYW1lcyhzY29yZV9tYXQpIDwtIHJvd0RhdGEoc2NvcmVzKSRuYW1lCgoKI3NhdmVSRFMoc2NvcmVzLCAidGFkX3Njb3JlcyIpCmBgYAoKCmBgYCN7cn0KZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gcm93U3VtcyhzY29yZV9tYXQpKSwgYmlucyA9IDIwMCkKYGBgCgoKYGBgI3tyfQojIGNvbXB1dGUgYWdncmVnYXRlcyBvZiBBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlIG1hdHJpeApkZWZhdWx0X2FyY2hyIDwtIGNyZWF0ZV9zZWFjZWxsX2FnZ3JlZ2F0ZXMoYXJjaHJfc2NvcmVzX21hdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYWNlbGxzKQojIGNvbXB1dGUgYWdncmVnYXRlcyBmb3IgdGFkIGJvdW5kYXJ5IEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmUgbWF0cml4CnRhZF9hcmNociA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKHNjb3JlX21hdCwgc2VhY2VsbHMpCiMgY29tcHV0ZSBhZ2dyZWdhdGVzIG9mIGdlbmUgZXhwcmVzc2lvbiBtYXRyaXgKcm5hX2h2ZyA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKGV4cHJfc3ViLCBzZWFjZWxscykKCiMgY29ycmVsYXRpb24gYmV0d2VlbiBnZW5lIGV4cHJlc3Npb24gdmFsdWVzIGFuZCBkZWZhdWx0IEFyY2hyIGdlbmUgYWN0aXZpdHkgc2NvcmVzCmRlZmF1bHRfYXJjaHJfY29yciA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhybmFfaHZnLCBkZWZhdWx0X2FyY2hyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBcmNoUiBnZW5lIGFjdGl2aXR5IHNjb3JlcywgU0VBY2VsbHMiKQojIGNvcnJlbGF0aW9uIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIGFuZCBUQUQgYm91bmRhcnkgZ2VuZSBhY3Rpdml0eSBzY29yZXMKdGFkX2NvcnIgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2h2ZywgdGFkX2FyY2hyLCAiQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMgd2l0aGluIFRBRCBib3VuZGFyaWVzLCBTRUFDZWxscyIpCgpjb3dwbG90OjpwbG90X2dyaWQoZGVmYXVsdF9hcmNocl9jb3JyW1syXV0sIHRhZF9jb3JyW1syXV0sIG5jb2wgPSAyKQoKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHggPSB0YWRfY29ycltbMV1dLCB5ID0gZGVmYXVsdF9hcmNocl9jb3JyW1sxXV1bbmFtZXModGFkX2NvcnJbWzFdXSldKSkgKwogIGdlb21fZGVuc2l0eV8yZF9maWxsZWQoYWVzKHggPSB0YWRfY29ycltbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGVmYXVsdF9hcmNocl9jb3JyW1sxXV1bbmFtZXModGFkX2NvcnJbWzFdXSldKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gLjUpICsKICBnZW9tX2xpbmUoYWVzKHggPSBkZWZhdWx0X2FyY2hyX2NvcnJbWzFdXSwgeSA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dKSwgY29sID0gInJlZCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICArCiAgbGFicyh4ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiAmIEFyY2hSIFRBRCBib3VuZGFyeSBzY29yZXMiLAogICAgICAgIHRpdGxlID0gIlJlc3RyaWN0aW5nIEFyY2hSIHNjb3JlcyB0byB3aXRoaW4gVEFEIGJvdW5kYXJpZXMiLAogICAgICAgIHkgPSAiQ29ycmVsYXRpb24gZ2VuZSBleHByZXNzaW9uICYgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMiKQoKYGBgCgoKIyMjIFRBRCBib3VuZGFyZXMgRTcuNQoKU2luY2UgdGhlIFRBRCBib3VuZGFyaWVzIHVzZWQgaGVyZSwgYXJlIGZyb20gZ2FzdHJ1bGF0aW9uIGRheSBFNy41LiBGb3IgdGhlIGxhdGVyCnRpbWUgcG9pbnRzIG5vIFRBRCBib3VuZGFyaWVzIGFyZSBhdmFpbGFibGUuIFRoZXJlZm9yZSwgaW4gdGhlIGZvbGxvd2luZyBJIHdpbGwgY2hlY2sgCmlmIHRoZSByZXN1bHRzIGltcHJvdmUgaW4gY29tcGFyaXNvbiB0byB0aGUgZGVmYXVsdCBBcmNoUiBmdW5jdGlvbiB3aGVuIHVzaW5nIG9ubHkgCmRhdGEgZnJvbSBFNy41LiBTaW5jZSBkdXJpbmcgZ2FzdHJ1bGF0aW9uIFRBRCBib3VuZGFyaWVzIG1pZ2h0IHN0aWxsIGJlIHZlcnkgCmR5bmFtaWMgdGhlIGltcHJvdmluZyBlZmZlY3Qgb2YgVEFEIGJvdW5kYXJpZXMgY291bGQgYmUgZGlsdXRlZCBieSBsYXRlciB0aW1lIHBvaW50cwppbiB0aGUgZGF0YS4gCgpXaGF0IGFyZSB0aCBnZW5lcyB3aGljaCBnZXQgemVybyBhY3Rpdml0eSBzY29yZXM/IERvIHRoZXkgbGllIG91dHNpZGUgdGhlIFRBRApib3VuZGFyaWVzPwoKYGBgI3tyfQplNzVfbWV0YSA8LSBjb2xEYXRhKHNjb3JlcykgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBmaWx0ZXIoU2FtcGxlICVpbiUgYygiRTcuNV9yZXAxIiwgIkU3LjVfcmVwMiIpKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCJjZWxsIikKbWF0Xzc1IDwtIHNjb3JlX21hdFtyb3duYW1lcyhzY29yZV9tYXQpICVpbiUgcm93bmFtZXMoZXhwcl9zdWIpLCBlNzVfbWV0YSRjZWxsXQpzZWFjZWxsc19zdWIgPC0gc2VhY2VsbHMgJT4lIGZpbHRlcihpbmRleCAlaW4lIGNvbG5hbWVzKG1hdF83NSkpIAoKIyBjb21wdXRlIGFnZ3JlZ2F0ZXMgb2YgQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZSBtYXRyaXgKZGVmYXVsdF9hcmNociA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKGFyY2hyX3Njb3Jlc19tYXRbcm93bmFtZXMoYXJjaHJfc2NvcmVzX21hdCkgJWluJQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd25hbWVzKGV4cHJfc3ViKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGU3NV9tZXRhJGNlbGxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VhY2VsbHNfc3ViKQojIGNvbXB1dGUgYWdncmVnYXRlcyBmb3IgdGFkIGJvdW5kYXJ5IEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmUgbWF0cml4CnRhZF9hcmNociA8LSBjcmVhdGVfc2VhY2VsbF9hZ2dyZWdhdGVzKG1hdF83NSwgc2VhY2VsbHNfc3ViKQojIGNvbXB1dGUgYWdncmVnYXRlcyBvZiBnZW5lIGV4cHJlc3Npb24gbWF0cml4CnJuYV9odmcgPC0gY3JlYXRlX3NlYWNlbGxfYWdncmVnYXRlcyhleHByX3N1YlssIGU3NV9tZXRhJGNlbGxdLCBzZWFjZWxsc19zdWIpCgojIGNvcnJlbGF0aW9uIGJldHdlZW4gZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhbmQgZGVmYXVsdCBBcmNociBnZW5lIGFjdGl2aXR5IHNjb3JlcwpkZWZhdWx0X2FyY2hyX2NvcnIgPC0gcm93d2lzZV9jb3JyZWxhdGlvbnMocm5hX2h2ZywgZGVmYXVsdF9hcmNociwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMsIFNFQWNlbGxzIikKIyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGdlbmUgZXhwcmVzc2lvbiBhbmQgVEFEIGJvdW5kYXJ5IGdlbmUgYWN0aXZpdHkgc2NvcmVzCnRhZF9jb3JyIDwtIHJvd3dpc2VfY29ycmVsYXRpb25zKHJuYV9odmcsIHRhZF9hcmNociwgIkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIHdpdGhpbiBUQUQgYm91bmRhcmllcywgU0VBQ2VsbHMiKQoKY293cGxvdDo6cGxvdF9ncmlkKGRlZmF1bHRfYXJjaHJfY29ycltbMl1dLCB0YWRfY29ycltbMl1dLCBuY29sID0gMikKCmdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gdGFkX2NvcnJbWzFdXSwgeSA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dW25hbWVzKHRhZF9jb3JyW1sxXV0pXSkpICsKICBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gdGFkX2NvcnJbWzFdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlZmF1bHRfYXJjaHJfY29ycltbMV1dW25hbWVzKHRhZF9jb3JyW1sxXV0pXSksCiAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IC41KSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gZGVmYXVsdF9hcmNocl9jb3JyW1sxXV0sIHkgPSBkZWZhdWx0X2FyY2hyX2NvcnJbWzFdXSksIGNvbCA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAgKwogIGxhYnMoeCA9ICJDb3JyZWxhdGlvbiBnZW5lIGV4cHJlc3Npb24gJiBBcmNoUiBUQUQgYm91bmRhcnkgc2NvcmVzIiwKICAgICAgICB0aXRsZSA9ICJSZXN0cmljdGluZyBBcmNoUiBzY29yZXMgdG8gd2l0aGluIFRBRCBib3VuZGFyaWVzIiwKICAgICAgICB5ID0gIkNvcnJlbGF0aW9uIGdlbmUgZXhwcmVzc2lvbiAmIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIikKYGBgCgpXaGF0IGFyZSB0aGUgZ2VuZXMgd2hpY2ggZ2V0IHplcm8gY29ycmVsYXRpb24gd2l0aCBnZW5lIGV4cHJlc3Npb24/CgpUaGVyZSBhcmUgOCBnZW5lcyB3aGljaCBnZXQgemVybyBjb3JyZWxhdGlvbiB2YWx1ZXMgYmV0d2VlbiBnZW5lIGFjdGl2aXR5IHNjb3JlcwphbmQgZ2VuZSBleHByZXNzaW9uLiBUaGlzIGlzLCBiZWNhdXNlIHRoZXkgZ2V0IHplcm8gYWN0aXZpdHkgc2NvcmVzIGluIGFsbCBjZWxscy4gSG93ZXZlciwKdGhlIHNhbWUgZ2VuZXMgYXJlIGV4cHJlc3NlZCB0byBjZXJ0YWluIGxldmVscyBhY2NvcmRpbmcgdG8gdGhlIGdlbmUgZXhwcmVzc2lvbiAKbWF0cml4LiBUd28gb2YgdGhlIGdlbmVzIGFsc28gZ2V0IHplcm8gYWN0aXZpdHkgc2NvcmVzIGluIHRoZSBkZWZhdWx0IEFyY2hSIApmdW5jdGlvbiAoUHJsMmMzLCBHc2RtYzQpLiBUaGUgcmVhc29uIGZvciBpcyBub3QgaW1tZWRpYXRlbHkgY2xlYXIsIHNpbmNlIGFzIGxvbmcKYXMgdGhlcmUgYXJlIHBlYWtzIGluIGEgZ2VuZSB3aW5kb3csIHRoZSBkaXN0YW5jZSB3ZWlnaHQgd2lsbCBhdCBsZWFzdCBiZSAwLjM2IAphY2NvcmluZGcgdG8gdGhlIGZvcm11bGEuIE9uZSByZWFzb24gZm9yIHplcm8gdmFsdWVzIGNvdWxkIGJlIHRoYXQgdGhlc2UgZ2VuZXMgbGllIG91dHNpZGUgVEFEIApib3VuZGFyaWVzIHdpY2ggaXMgaW4gZmFjdCB0aGUgY2FzZSBmb3IgZm91ciBvdXQgb2YgOCBnZW5lcy4KCgpXaGF0IGlzIHRoZSBleHBsYW5hdGlvbiB3aHkgTHl6MiBhbmQgR20xMzU0NyAgZ2V0IGFjdGl2aXR5IHNjb3JlcyBvZiB6ZXJvPwoKYGBgI3tyfQp6ZXJvX2dlbmVzIDwtIG5hbWVzKHRhZF9jb3JyW1sxXV1bdGFkX2NvcnJbWzFdXSA9PSAwXSkKCnplcm9fbWF0IDwtIHNjb3JlX21hdFt6ZXJvX2dlbmVzLCBdCnJvd1N1bXMoemVyb19tYXQpIAoKCiMgY2hlY2sgdGhlIGRlZmF1bHQgQXJjaFIgc2NvcmVzIGZvciB0aGVzZSBnZW5lcwpyb3dTdW1zKGFyY2hyX3Njb3Jlc19tYXRbemVyb19nZW5lcywgXSkKCiMgY2hlY2sgdGhlIGdlbmUgZXhwcmVzc2lvbiBjb3V0bnMgZm9yIHRoZXNlIGdlbmVzCnJvd1N1bXMoZXhwcl9tYXRbemVyb19nZW5lcyxdKQoKCnAyZ19wb3MgPC0gcDJnICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIGZpbHRlcihDb3JyZWxhdGlvbiA+IDApICU+JQogIHVuaXRlKGxpbmssIGlkeFJOQSwgaWR4QVRBQywgc2VwID0gIiUiLCByZW1vdmUgPSBGQUxTRSkKCmdlbmVfYW5ub19hbGwgPC0gcm93RGF0YShnZW5lX2V4cHIpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgbXV0YXRlKGlkeFJOQSA9IHNlcShucm93KC4pKSkgJT4lIAogIGZpbHRlcihpZHhSTkEgJWluJSBwMmdfcG9zJGlkeFJOQSkgJT4lCiAgbXV0YXRlKHN0cmFuZCA9IGlmZWxzZShzdHJhbmQgPT0gMSwgIisiLCAiLSIpKSAlPiUKICBtdXRhdGUoc3RhcnRfY29vcmQgPSBpZmVsc2Uoc3RyYW5kID09ICIrIiwgc3RhcnQsIGVuZCkpICU+JSAKICByZW5hbWUoZ2VuZSA9IG5hbWUpICMlPiUgR1JhbmdlcygpCgojIHN1YnNldCBhdGFjIGdyYW5nZXMgJiBnZXQgbWlkZGxlIG9mIGVhY2ggcGVhawpwb3NfYXRhY19ncmFuZ2VzX2FsbCA8LSBtZXRhZGF0YShwMmcpW1sxXV0gICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgbXV0YXRlKGlkeEFUQUMgPSBzZXEobnJvdyguKSkpICU+JSAKICAjIGdyb3VwX2J5KHNlcW5hbWVzKSAlPiUKICAjIG11dGF0ZShpZHggPSBzZXFfYWxvbmcoc2VxbmFtZXMpKSAlPiUgCiAgIyB1bmdyb3VwICU+JQogICN0aWR5cjo6dW5pdGUoY2hyX2lkeCwgc2VxbmFtZXMsIGlkeCwgcmVtb3ZlID0gRkFMU0UsIHNlcCA9ICJfIikgJT4lIAogIGZpbHRlcihpZHhBVEFDICVpbiUgcDJnX3BvcyRpZHhBVEFDKSAlPiUgCiAgbXV0YXRlKG1pZGRsZSA9IHN0YXJ0ICsgMzAwKSAjJT4lIEdSYW5nZXMoKSAKCgoKIyBjb21iaW5lIHRoZSB0aHJlZSBkYXRhZnJhbWVzCnAyZ19qb2luX2FsbCA8LSBsZWZ0X2pvaW4ocDJnX3BvcywgYXMuZGF0YS5mcmFtZShwb3NfYXRhY19ncmFuZ2VzX2FsbCksCiAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhBVEFDIikKcDJnX2pvaW5fYWxsIDwtIGxlZnRfam9pbihwMmdfam9pbl9hbGwsIGFzLmRhdGEuZnJhbWUoZ2VuZV9hbm5vX2FsbCksCiAgICAgICAgICAgICAgICAgICAgICBieSA9ICJpZHhSTkEiLCBzdWZmaXggPSBjKCIuYXRhYyIsICIucm5hIikpCgoKcDJnX2pvaW5fYWxsIDwtIHAyZ19qb2luX2FsbCAlPiUgCiAgbXV0YXRlKGRpc3RhbmNlID0gYWJzKHN0YXJ0X2Nvb3JkIC0gbWlkZGxlKSkKCgoKICAjIGZpbmQgb3ZlcmxhcHBpbmcgcGVha3MgYW5kIGdlbmUgd2luZG93IGluIGNocm9tb3NvbWUtYXdhcmUgZmFzaGlvbgp0YWRfb3ZlcmxhcHNfZ2VuZXMgPC0gKGZpbmRPdmVybGFwcyhnZW5lX2Fubm9fYWxsICU+JSBHUmFuZ2VzKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFkX2JvdW5kYXJpZXMpKQoKCiMgZ2V0IGFsbCBnZW5lcyB3aGljaCBhcmUgZm91bmQgd2l0aGluIHRhZCBib3VkbmFyaWVzCmdlbmVfYW5ub193aXRoaW5fdGFkIDwtIGdlbmVfYW5ub19hbGxbcXVlcnlIaXRzKHRhZF9vdmVybGFwc19nZW5lcyksXQoKCiMgTGV0cyBleGFtaW5lIHRoZSBnZW5lcyB3aGljaCBhcmUgZm91bmQgd2l0aGluIHRhZCBib3VuZGFyaWVzLCBidXQKIyBnZXQgYW4gYWN0aXZpdHkgc2NvcmUgb2YgemVybyBuZXZlcnRoZWxlc3MKZ2VuZV9hbm5vX3dpdGhpbl90YWQgJT4lIGZpbHRlcihnZW5lICVpbiUgemVyb19nZW5lcykKCgpnZW5lX25hbWUgPSAiTHl6MiIKY2hyX25hbWUgPSAiY2hyMiIKY2hyeCA8LSB0YWRfYm91bmRhcmllcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBmaWx0ZXIoc2VxbmFtZXMgPT0gY2hyX25hbWUpICU+JUdSYW5nZXMoKQpoaXRzIDwtIGZpbmRPdmVybGFwcyhnZW5lX2Fubm9fYWxsICU+JSBmaWx0ZXIoZ2VuZSA9PSBnZW5lX25hbWUpICU+JSBHUmFuZ2VzKCksICBjaHJ4KQpzdGFydF90YWQgPC0gc3RhcnQoY2hyeFtzdWJqZWN0SGl0cyhoaXRzKSxdKQplbmRfdGFkIDwtIGVuZChjaHJ4W3N1YmplY3RIaXRzKGhpdHMpLF0pCnN0YXJ0X2dlbmUgPC0gc3RhcnQoZ2VuZV9hbm5vX2FsbCAlPiUgZmlsdGVyKGdlbmUgPT0gZ2VuZV9uYW1lKSAlPiUgR1JhbmdlcygpKQplbmRfZ2VuZSA8LSBlbmQoZ2VuZV9hbm5vX2FsbCAlPiUgZmlsdGVyKGdlbmUgPT0gZ2VuZV9uYW1lKSAlPiUgR1JhbmdlcygpKQpwcmludChwYXN0ZTAoIk91dCBvZiAiLCBsZW5ndGgoemVyb19nZW5lcyksICIgZ2VuZXMsICAiLCAgbGVuZ3RoKHplcm9fZ2VuZXNbemVyb19nZW5lcyAlaW4lIGdlbmVfYW5ub193aXRoaW5fdGFkJGdlbmVdKSAsICIgZ2VuZXMgYXJlIGZvdW5kIHdpdGhpbiB0YWQgYm91bmRhcmllcywgd2hpbGUgdGhlIHJlc3QgYXJlIG5vdC4iKSkKcG9zX2F0YWNfZ3Jhbmdlc19hbGwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZmlsdGVyKHNlcW5hbWVzID09IGNocl9uYW1lKSAlPiUKICBmaWx0ZXIoc3RhcnQgPiBzdGFydF90YWQgJiBlbmQgPCBlbmRfdGFkKQoKIyAKIyB6ZXJvX2dlbmVzCiMgCiMgaWR4IDwtIChnZW5lX2Fubm9fYWxsICU+JSBmaWx0ZXIoZ2VuZSAlaW4lIHplcm9fZ2VuZXMpKSRpZHhSTkEKIyAKIyBpZHggJWluJSBnZW5lX2Fubm9fYWxsW3RhZF9vdmVybGFwc19nZW5lcyRxdWVyeUhpdHMsCmBgYAoKCgojIyBBcmNoUiBHZW5lIEFjdGl2aXR5IFNjb3JlcyB1c2luZyBnZW5lIGJvZHkKCjxkZXRhaWxzPgo8c3VtbWFyeT5BcmNoUiBHZW5lIEFjdGl2aXR5IFNjb3JlcyB1c2luZyBnZW5lIGJvZHk8L3N1bW1hcnk+CgpgYGAje3J9Cgojc2F2ZUFyY2hSUHJvamVjdChBcmNoUlByb2ogPSBwcm9qLCBvdXRwdXREaXJlY3RvcnkgPSAiMTJfQ29weTQvIiwgbG9hZCA9IEZBTFNFKQpsb2FkQXJjaFJQcm9qZWN0KCIxMl9hY3Rpdml0eV9zY29yZXNfZ2VuZV9ib2R5X3BlYWtzLyIpCgpwcm9qIDwtIGFkZEthdGhpR2VuZVNjb3JlTWF0cml4KAogIHByb2osCiAgZ2VuZXMgPSBnZXRHZW5lcyhwcm9qKSwKICBwZWFrcyA9IGdldFBlYWtTZXQocHJvaiksCiAgZ2VuZU1vZGVsID0gImV4cCgtYWJzKHgpLzUwMDApICsgZXhwKC0xKSIsCiAgbWF0cml4TmFtZSA9ICJHZW5lU2NvcmVNYXRyaXgiLAogIGV4dGVuZFVwc3RyZWFtID0gYygxMDAwLCAxMDAwMDApLAogIGV4dGVuZERvd25zdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiAgI2dlbmVVcHN0cmVhbSA9IDUwMDAsICNOZXcgUGFyYW0KICAjZ2VuZURvd25zdHJlYW0gPSAwLCAjTmV3IFBhcmFtCiAgdXNlR2VuZUJvdW5kYXJpZXMgPSBUUlVFLAogIHVzZVRTUyA9IEZBTFNFLCAjTmV3IFBhcmFtCiAgZXh0ZW5kVFNTID0gRkFMU0UsCiAgdGlsZVNpemUgPSA1MDAsCiAgY2VpbGluZyA9IDQsCiAgZ2VuZVNjYWxlRmFjdG9yID0gNSwgI05ldyBQYXJhbQogIHNjYWxlVG8gPSAxMDAwMCwKICBleGNsdWRlQ2hyID0gYygiY2hyWSIsICJjaHJNIiksCiAgYmxhY2tsaXN0ID0gZ2V0QmxhY2tsaXN0KHByb2opLAogIHRocmVhZHMgPSAxLAogIHBhcmFsbGVsUGFyYW0gPSBOVUxMLAogIHN1YlRocmVhZGluZyA9IFRSVUUsCiAgZm9yY2UgPSBUUlVFLAogIGxvZ0ZpbGUgPSBjcmVhdGVMb2dGaWxlKCIuYWRkS2F0aGlHZW5lU2NvcmVNYXQiKSkKCgpzY29yZXMgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgdXNlTWF0cml4ID0gIkdlbmVTY29yZU1hdHJpeCIpCgpzY29yZXNfbWF0IDwtIGFzc2F5cyhzY29yZXMpW1sxXV0Kcm93bmFtZXMoc2NvcmVzX21hdCkgPC0gcm93RGF0YShzY29yZXMpJG5hbWUKCgojIHNjZSA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChsaXN0KHNjb3Jlcz1zY29yZXNfbWF0KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd0RhdGEgPSBhcy5kYXRhLmZyYW1lKHJvd0RhdGEoc2NvcmVzKSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gYXMuZGF0YS5mcmFtZShjb2xuYW1lcyhzY29yZXNfbWF0KSkpCiMgCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL2FyY2hyX3Njb3Jlc19nZW5lX2JvZHlfcGVha19iYXNlZCIsIFhfbmFtZSA9ICJzY29yZXMiKQoKYGBgCjwvZGV0YWlscz4KCkNvcnJlbGF0aW5nIGdlbmUgZXhwcmVzc2lvbiB3aXRoIGFjdGl2aXR5IHNjb3JlczoKCmBgYCN7cn0KYXJjaHJfZ2VuZV9ib2R5X2FnZyA8LSBrbm5fYWdncmVnYXRlcyhzY29yZXNfbWF0LCBjZWxsX2FnZ19saXN0KQoKZ2VuZV9ib2R5X2tubiA8LSByb3d3aXNlX2NvcnJlbGF0aW9ucyhybmFfYWdnLCBhcmNocl9nZW5lX2JvZHlfYWdnLCAiQXJjaFIgZ2VuZSBhY3Rpdml0eSBzY29yZXMgYmFzZWQgb24gcGVhayBtYXRyaXgsIHVzaW5nIGdlbmUgYm9keSIpCgoKY293cGxvdDo6cGxvdF9ncmlkKGFyY2hyX2tubltbMl1dLCBnZW5lX2JvZHlfa25uW1syXV0sIG5jb2wgPSAyKQoKcDEgPC0gZ2dwbG90KCkgKyBnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKGFlcyh4ID0gZ2VuZV9ib2R5X2tubltbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYXJjaHJfa25uW1sxXV0pLCBhbHBoYSA9IC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGdlbmVfYm9keV9rbm5bWzFdXSwgeSA9IGFyY2hyX2tubltbMV1dKSkgKwogIGdlb21fbGluZShhZXMoeCA9IGdlbmVfYm9keV9rbm5bWzFdXSwgeSA9IGdlbmVfYm9keV9rbm5bWzFdXSksIGNvbCA9ICJyZWQiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSAKYGBgCgoKIyMgQXJjaFIgR2VuZSBBY3Rpdml0eSBTY29yZXMgdXNpbmcgVFNTLCBubyBnZW5lIGJvZHkKCjxkZXRhaWxzPgo8c3VtbWFyeT5BcmNoUiBHZW5lIEFjdGl2aXR5IFNjb3JlcyB1c2luZyBUU1MsIG5vIGdlbmUgYm9keTwvc3VtbWFyeT4KCgpgYGAje3J9Cgpwcm9qIDwtIGxvYWRBcmNoUlByb2plY3QoIjEyX2FjdGl2aXR5X3Njb3Jlc19UU1NfdGlsZXMvIikKCnByb2ogPC0gYWRkR2VuZVNjb3JlTWF0cml4KAogIHByb2osCiAgZ2VuZXMgPSBnZXRHZW5lcyhwcm9qKSwKICBnZW5lTW9kZWwgPSAiZXhwKC1hYnMoeCkvNTAwMCkiLAogIG1hdHJpeE5hbWUgPSAiR2VuZVNjb3JlTWF0cml4IiwKICBleHRlbmRVcHN0cmVhbSA9IGMoMTAwMCwgMTAwMDAwKSwKICBleHRlbmREb3duc3RyZWFtID0gYygxMDAwLCAxMDAwMDApLAogICNnZW5lVXBzdHJlYW0gPSA1MDAwLCAjTmV3IFBhcmFtCiAgI2dlbmVEb3duc3RyZWFtID0gMCwgI05ldyBQYXJhbQogIHVzZUdlbmVCb3VuZGFyaWVzID0gVFJVRSwKICB1c2VUU1MgPSBUUlVFLCAjTmV3IFBhcmFtCiAgZXh0ZW5kVFNTID0gRkFMU0UsCiAgdGlsZVNpemUgPSA1MDAsCiAgY2VpbGluZyA9IDQsCiAgZ2VuZVNjYWxlRmFjdG9yID0gNSwgI05ldyBQYXJhbQogIHNjYWxlVG8gPSAxMDAwMCwKICBleGNsdWRlQ2hyID0gYygiY2hyWSIsICJjaHJNIiksCiAgYmxhY2tsaXN0ID0gZ2V0QmxhY2tsaXN0KHByb2opLAogIHRocmVhZHMgPSAxLAogIHBhcmFsbGVsUGFyYW0gPSBOVUxMLAogIHN1YlRocmVhZGluZyA9IFRSVUUsCiAgZm9yY2UgPSBUUlVFLAogIGxvZ0ZpbGUgPSBjcmVhdGVMb2dGaWxlKCIuYWRkR2VuZVNjb3JlTWF0cml4IikpCgoKc2NvcmVzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2osIHVzZU1hdHJpeCA9ICJHZW5lU2NvcmVNYXRyaXgiKQoKc2NvcmVzX21hdCA8LSBhc3NheXMoc2NvcmVzKVtbMV1dCnJvd25hbWVzKHNjb3Jlc19tYXQpIDwtIHJvd0RhdGEoc2NvcmVzKSRuYW1lCgoKIyBzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChzY29yZXM9c2NvcmVzX21hdCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dEYXRhID0gYXMuZGF0YS5mcmFtZShyb3dEYXRhKHNjb3JlcykpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGFzLmRhdGEuZnJhbWUoY29sbmFtZXMoc2NvcmVzX21hdCkpKQojIAojIHdyaXRlSDVBRChzY2UsICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL3AyZ19nZW5lX2FjdGl2aXR5X3Njb3Jlcy9hcmNocl9zY29yZXNfdHNzIiwgWF9uYW1lID0gInNjb3JlcyIpCgpgYGAKCiMjIEFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGNvbXB1dGVkIHVzaW5nIFRTUywgbm8gZ2VuZSBib2R5IGFuZCBQZWFrTWF0cml4IGluc3RlYWQgb2YgVGlsZU1hdHJpeAoKPGRldGFpbHM+CjxzdW1tYXJ5PkFyY2hSIGdlbmUgYWN0aXZpdHkgc2NvcmVzIGNvbXB1dGVkIHVzaW5nIFRTUywgbm8gZ2VuZSBib2R5IGFuZCBQZWFrTWF0cml4IGluc3RlYWQgb2YgVGlsZU1hdHJpeDwvc3VtbWFyeT4KCmBgYCN7cn0KcHJvaiA8LSBsb2FkQXJjaFJQcm9qZWN0KCIxMl9hY3Rpdml0eV9zY29yZXNfVFNTX3BlYWtzLyIpCgpwcm9qIDwtIGFkZEthdGhpR2VuZVNjb3JlTWF0cml4KAogIHByb2osCiAgZ2VuZXMgPSBnZXRHZW5lcyhwcm9qKSwKICBwZWFrcyA9IGdldFBlYWtTZXQocHJvaiksCiAgZ2VuZU1vZGVsID0gImV4cCgtYWJzKHgpLzUwMDApIiwKICBtYXRyaXhOYW1lID0gIkdlbmVTY29yZU1hdHJpeCIsCiAgZXh0ZW5kVXBzdHJlYW0gPSBjKDEwMDAsIDEwMDAwMCksCiAgZXh0ZW5kRG93bnN0cmVhbSA9IGMoMTAwMCwgMTAwMDAwKSwKICAjZ2VuZVVwc3RyZWFtID0gNTAwMCwgI05ldyBQYXJhbQogICNnZW5lRG93bnN0cmVhbSA9IDAsICNOZXcgUGFyYW0KICB1c2VHZW5lQm91bmRhcmllcyA9IFRSVUUsCiAgdXNlVFNTID0gVFJVRSwgI05ldyBQYXJhbQogIGV4dGVuZFRTUyA9IEZBTFNFLAogIHRpbGVTaXplID0gNTAwLAogIGNlaWxpbmcgPSA0LAogIGdlbmVTY2FsZUZhY3RvciA9IDUsICNOZXcgUGFyYW0KICBzY2FsZVRvID0gMTAwMDAsCiAgZXhjbHVkZUNociA9IGMoImNoclkiLCAiY2hyTSIpLAogIGJsYWNrbGlzdCA9IGdldEJsYWNrbGlzdChwcm9qKSwKICB0aHJlYWRzID0gMSwKICBwYXJhbGxlbFBhcmFtID0gTlVMTCwKICBzdWJUaHJlYWRpbmcgPSBUUlVFLAogIGZvcmNlID0gVFJVRSwKICBsb2dGaWxlID0gY3JlYXRlTG9nRmlsZSgiLmFkZEthdGhpR2VuZVNjb3JlTWF0IikpCgpzY29yZXMgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgdXNlTWF0cml4ID0gIkdlbmVTY29yZU1hdHJpeCIpCgpzY29yZXNfbWF0IDwtIGFzc2F5cyhzY29yZXMpW1sxXV0Kcm93bmFtZXMoc2NvcmVzX21hdCkgPC0gcm93RGF0YShzY29yZXMpJG5hbWUKCiMKIyBzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChzY29yZXM9c2NvcmVzX21hdCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dEYXRhID0gYXMuZGF0YS5mcmFtZShyb3duYW1lcyhzY29yZXNfbWF0KSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gYXMuZGF0YS5mcmFtZShjb2xuYW1lcyhzY29yZXNfbWF0KSkpCiMgCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL2FyY2hyX3Njb3Jlc19wZWFrX2Jhc2VkIiwgWF9uYW1lID0gInNjb3JlcyIpCmBgYAoKYGBgI3tyfQoKCgojIHNjZSA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChsaXN0KHAyZ19tYXQgPSBwMmdfbWF0KSkKIyAKIyB3cml0ZUg1QUQoc2NlLCAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS9qdXB5dGVyX25vdGVib29rcy9wMmdfZ2VuZV9hY3Rpdml0eV9zY29yZXMvcDJnX21hdF8yNTBrYiIsCiMgICAgICAgICAgIFhfbmFtZSA9ICJwMmdfbWF0IikKCiMgCiMgCiMgc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGxpc3QocGVha19tYXQgPSBwZWFrX21hdCkpCiMgCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL3BlYWtfbWF0IiwKIyAgICAgICAgICAgWF9uYW1lID0gInBlYWtfbWF0IikKCgojIGNwX25hbWVzIDwtIGNvbG5hbWVzKGNvbERhdGEoZ2VuZV9leHByKSkKIyBjcF9uYW1lc1syMF0gPC0gImNlbGx0eXBlcyIKIyBjb2xuYW1lcyhjb2xEYXRhKGdlbmVfZXhwcikpIDwtIGNwX25hbWVzCgpzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChnZW5lcyA9IGV4cHJfbWF0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgI3Jvd0RhdGEgPSBhcy5kYXRhLmZyYW1lKHJvd25hbWVzKGdlbmVfZXhwcikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gYXMuZGF0YS5mcmFtZShjb2xEYXRhKGdlbmVfZXhwcikpKQoKIyB3cml0ZUg1QUQoc2NlLCAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS9qdXB5dGVyX25vdGVib29rcy9wMmdfZ2VuZV9hY3Rpdml0eV9zY29yZXMvZ2VuZV9leHByX21hdCIsCiMgICAgICAgICAgIFhfbmFtZSA9ICJnZW5lcyIpCiMgCiMgCiMgI3AyZ19tYXRfbm9ybSA8LSBwMmdfbWF0IC8gcm93U3VtcyhwMmdfbWF0KQojIHNjb3JlcyA8LSBwMmdfbWF0ICUqJSBwZWFrX21hdAojIHNjb3JlcyA8LSB0KHQoc2NvcmVzKSAvIGNvbFN1bXMoc2NvcmVzKSkKIyBzdG9waWZub3QoYW55KGlzLm5hKHNjb3JlcykpID09IEZBTFNFKQojIHNjb3Jlc0B4IDwtIHBtaW4oMWU5LCBleHAoc2NvcmVzQHgpIC0gMSkKIyAKIyAKIyAKIyBzY2UgPC0gU2luZ2xlQ2VsbEV4cGVyaW1lbnQobGlzdChpbnZlc3RpZ2F0aW9uID0gaW52ZXN0aWdhdGlvbikpCiMgCiMgd3JpdGVINUFEKHNjZSwgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvcDJnX2dlbmVfYWN0aXZpdHlfc2NvcmVzL2ludmVzdGlnYXRpb25fc2NvcmVzIiwKIyAgICAgICAgICAgWF9uYW1lID0gImludmVzdGlnYXRpb24iKQoKCgoKCiMgbGF0ZW50IGVtYmVkZGluZwplbWIgPC0gZ2V0UmVkdWNlZERpbXMoCiAgQXJjaFJQcm9qID0gcHJvaiwKICByZWR1Y2VkRGltcyA9ICJhdGFjX0xTSV8xMDAwMDAiLAogIHJldHVybk1hdHJpeCA9IFRSVUUsCiAgZGltc1RvVXNlID0gMTozMCwKICBzY2FsZURpbXMgPSBOVUxMLAogIGNvckN1dE9mZiA9IDAuNzUKKQpkaW0oZW1iKQoKCnNjZSA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChsaXN0KGVtYmVkZGluZyA9IGVtYikpCgp3cml0ZUg1QUQoc2NlLCAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS9qdXB5dGVyX25vdGVib29rcy9wMmdfZ2VuZV9hY3Rpdml0eV9zY29yZXMvYXJjaHJfbHNpX2VtYmVkZGluZyIsCiAgICAgICAgICBYX25hbWUgPSAiZW1iZWRkaW5nIikKCgpgYGA=